module Killbill #:nodoc:
  module PaypalExpress #:nodoc:
    class PrivatePaymentPlugin < ::Killbill::Plugin::ActiveMerchant::PrivatePaymentPlugin

      ONE_HOUR_AGO = 3600
      STATUS = {:CAPTURE   => {:success_status => 'Completed', :type => 'Payment'},
                :AUTHORIZE => {:success_status => 'Pending',   :type => 'Authorization'},
                :REFUND    => {:success_status => 'Completed', :type => 'Refund'}}

      def initialize(session = {})
        super(:paypal_express,
              ::Killbill::PaypalExpress::PaypalExpressPaymentMethod,
              ::Killbill::PaypalExpress::PaypalExpressTransaction,
              ::Killbill::PaypalExpress::PaypalExpressResponse,
              session)
      end

      # See https://cms.paypal.com/uk/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECReferenceTxns
      def initiate_express_checkout(kb_account_id, kb_tenant_id, amount_in_cents=0, currency='USD', with_baid=true, options = {})
        options[:currency]          ||= currency

        # Required arguments
        options[:return_url]        ||= 'http://www.example.com/success'
        options[:cancel_return_url] ||= 'http://www.example.com/sad_panda'

        if with_baid
          options[:billing_agreement]               ||= {}
          options[:billing_agreement][:type]        ||= 'MerchantInitiatedBilling'
          options[:billing_agreement][:description] ||= 'Kill Bill billing agreement'
        end

        # Go to Paypal (SetExpressCheckout call)
        payment_processor_account_id = options[:payment_processor_account_id] || :default
        paypal_express_response      = gateway(payment_processor_account_id, kb_tenant_id).setup_authorization(amount_in_cents, options)
        response, transaction        = save_response_and_transaction(paypal_express_response, :initiate_express_checkout, kb_account_id, kb_tenant_id, payment_processor_account_id)

        response
      end

      def to_express_checkout_url(response, kb_tenant_id = nil, options = {})
        payment_processor_account_id = options[:payment_processor_account_id] || :default
        gateway                      = gateway(payment_processor_account_id, kb_tenant_id)
        review                       = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :review)
        gateway.redirect_url_for(response.token, :review => review)
      end

      def get_external_keys_for_accounts(kb_account_ids, kb_tenant_id)
        context = kb_apis.create_context(kb_tenant_id)
        kb_account_ids.map {|id| kb_apis.account_user_api.get_account_by_id(id, context).external_key }
      end

      def fix_unknown_transaction(plugin_response, trx_plugin_info, gateway, kb_account_id, kb_tenant_id)
        status, transaction_id, type = search_transaction(trx_plugin_info.created_date - ONE_HOUR_AGO,
                                                          trx_plugin_info.amount,
                                                          trx_plugin_info.currency,
                                                          gateway,
                                                          trx_plugin_info.kb_transaction_payment_id)
        return false if status.blank? || transaction_id.blank? || type.blank?

        if type == STATUS[trx_plugin_info.transaction_type][:type] &&
           status == STATUS[trx_plugin_info.transaction_type][:success_status]
          plugin_response.transition_to_success transaction_id, trx_plugin_info
          logger.info("Fixed UNDEFINED kb_transaction_id='#{trx_plugin_info.kb_transaction_payment_id}' to PROCESSED")
          return true
        end

        false
      end

      def search_transaction(start_time, amount, currency, gateway, kb_payment_transaction_id)
        options = {:start_date => start_time, :invoice_id => kb_payment_transaction_id, :amount => amount, :currency => currency}
        response = gateway.transaction_search options
        [response.params['status'], response.authorization, response.params['type']]
      end
    end
  end
end