module Skr

    # A payment can be for either incoming or outgoing, if incoming must
    # be associated with an Invoice, otherwise a Vendor or PaymentCategory
    class Payment < Model

        SEQUENTIAL_ID_PREFIX = 'Pmnt-'

        has_visible_id
        has_random_hash_code
        has_gl_transaction

        belongs_to :category,     class_name: 'Skr::PaymentCategory', export: true
        belongs_to :vendor,       class_name: 'Skr::Vendor',          export: true
        belongs_to :invoice,      class_name: 'Skr::Invoice',         export: true
        belongs_to :bank_account, class_name: 'Skr::BankAccount',     export: true
        belongs_to :location,     class_name: 'Skr::Location',        export: true

        validates :name, :amount, :bank_account, presence: true

        attr_accessor :credit_card
        whitelist_attributes :credit_card

        has_one :gl_transaction, class_name: 'Skr::GlTransaction', as: :source

        before_validation :set_defaults, on: :create
        before_validation :attempt_charging_provided_card,
                          on: :create, if: :credit_card

        after_save :apply_transaction

        def latex_template_variables
            { 'position' => :absolute }
        end

        def incoming?
            vendor.present?
        end

        def outgoing?
            vendor.present? || category.present?
        end

      private

        def attempt_charging_provided_card
            return unless credit_card.present?

            card = ActiveMerchant::Billing::CreditCard.new(credit_card)
            gw = Skr::MerchantGateway.get
            resp = gw.purchase(amount, card)
            if resp.success?
                metadata['authorization'] = resp.authorization
            else
                errors.add(:credit_card, "purchase failed: #{resp.message}")
            end
        end

        def gl_accounts
            if vendor
                [vendor.gl_payables_account, bank_account.gl_account]
            elsif invoice
                [bank_account.gl_account,
                 invoice.customer.gl_receivables_account]
            else
                [category.gl_account, bank_account.gl_account]
            end
        end

        def apply_transaction
            (credit, debit) = gl_accounts
            GlTransaction.push_or_save(
                owner:  self,  amount: amount,
                debit:  debit, credit: credit
            )
        end

        def set_defaults
            self.location     ||= Location.default
            self.date         ||= Date.today
            if name.blank?
                if self.vendor
                    self.name = vendor.name
                elsif self.invoice
                    self.name = invoice.billing_address.name
                end
            end
            if bank_account && outgoing?
                self.check_number ||= SequentialId.next_for(SEQUENTIAL_ID_PREFIX + bank_account.id.to_s)
            end
            self.bank_account ||= BankAccount.default
        end

    end
end