// License: LGPL-3.0-or-later
// Include the cards/fields partial to use with this.
// Call appl.card_form.create(card_obj) to start the card creation process.
// Use the appl.card_form.on_fail callback to handle failures.
// Use the appl.card_form.on_complete callback to handle completion.
// This does not create any donations -- do the donation creation inside appl.card_form.on_complete.

// Not namespacing card_form; only show one card form on the page at any time

var request = require('../common/super-agent-promise')
var format_err = require('../common/format_response_error')

module.exports = create_card

// UI state defaults
appl.def('card_form', {
	loading: false,
	error: false,
	status: '',
	on_complete: function() {},
	on_fail: function() {},
	progress_width: '0%' // Width of the progress bar
})

// Define some status messages and progress bar widths for each step of the process
var statuses = {
	before_tokenization: {
		progress_width: '20%',
		status: 'Double-checking your card...'
	},
	before_create: {
		progress_width: '75%',
		status: 'Looks good! Sending the carrier pigeons...'
	},
	on_complete: {
			progress_width: '100%',
			status: 'Processing payment...'
	}
}

// Tokenize with stripe, then save to our db.
// The first argument must be a holder object that has 'type' and 'id' keys.
// eg: {holder: {type: 'Nonprofit', id: 1}}
function create_card(holder, card_obj, options) {
  options = options || {}
	if(appl.card_form.loading) return
	appl.def('card_form', { loading: true, error: false })
	appl.def('card_form', statuses.before_tokenization)

  // Delete the cvc key from card_obj if
  // the value of cvc is a blank string.
  // Otherwise, Stripe will return an error for
  // incorrect security code.
  if(card_obj.cvc === '') {
    delete card_obj['cvc']
  }

	// First, tokenize the card with Stripe.js
	return tokenize_with_stripe(card_obj)
		.catch(display_stripe_err)
		// Then, save a Card record in our db
		.then(function(stripe_resp) {
			appl.def('card_form', statuses.before_create)
			return create_record(holder, stripe_resp, options)
		})
		.then(function(resp) {
			appl.def('card_form', statuses.on_complete)
			return resp.body
		})
		.catch(display_err)
}

// Post to stripe to get back a stripe_card_token
function tokenize_with_stripe(card_obj) {
	return new Promise(function(resolve, reject) {
		Stripe.card.createToken(card_obj, function(status, resp) {
			if(resp.error) reject(resp)
			else resolve(resp)
		})
	})
}

// Save a record of the card in our own db
function create_record(holder, stripe_resp, options={}) {
	var output = {card: {
            holder_type: holder.type,
            holder_id: holder.id,
            email: holder.email,
            cardholders_name: stripe_resp.name,
            name: stripe_resp.card.brand + ' *' + stripe_resp.card.last4,
            stripe_card_token: stripe_resp.id,
            stripe_card_id: stripe_resp.card.id
        }}
	if (options['event_id'])
	{
		output['event_id'] = options['event_id']
	}

	return request.post(options.path || '/cards')
		.send(output)
		.perform()
}

// Set UI state to display an error in the card form.
function display_err(resp) {
  if(resp && resp.body) {
    appl.def('card_form', {
      loading: false,
      error: true,
      status: format_err(resp),
      progress_width: '0%'
    })
    appl.def('loading', false)
  }
}

function display_stripe_err(resp) {
  if(resp && resp.error) {
    appl.def('card_form', {
      loading: false,
      error: true,
      status: resp.error.message,
      progress_width: '0%'
    })
		appl.def('loading', false)
		
		throw new Error()
  }
}