module ActiveMerchant #:nodoc:
  module Billing #:nodoc:
    class PaySecureGateway < Gateway
      self.live_url = self.test_url = 'https://clearance.commsecure.com.au/cgi-bin/PSDirect'

      self.money_format = :cents

      # Currently Authorization and Capture is not implemented because
      # capturing requires the original credit card information
      TRANSACTIONS = {
        purchase: 'PURCHASE',
        authorization: 'AUTHORISE',
        capture: 'ADVICE',
        credit: 'REFUND'
      }

      SUCCESS = 'Accepted'
      SUCCESS_MESSAGE = 'The transaction was approved'

      self.supported_countries = ['AU']
      self.homepage_url = 'http://www.commsecure.com.au/paysecure.shtml'
      self.display_name = 'PaySecure'
      self.supported_cardtypes = %i[visa master american_express diners_club]

      def initialize(options = {})
        requires!(options, :login, :password)
        super
      end

      def purchase(money, credit_card, options = {})
        requires!(options, :order_id)

        post = {}
        add_amount(post, money)
        add_invoice(post, options)
        add_credit_card(post, credit_card)

        commit(:purchase, money, post)
      end

      private

      # Used for capturing, which is currently not supported.
      def add_reference(post, identification)
        auth, trans_id = identification.split(';')
        post[:authnum] = auth
        post[:transid] = trans_id
      end

      def add_amount(post, money)
        post[:amount] = amount(money)
      end

      def add_invoice(post, options)
        post[:merchant_transid] = options[:order_id].to_s.slice(0, 21)
        post[:memnum]           = options[:invoice]
        post[:custnum]          = options[:customer]
        post[:clientdata]       = options[:description]
      end

      def add_credit_card(post, credit_card)
        post[:cardnum]  = credit_card.number
        post[:cardname] = credit_card.name
        post[:expiry]   = expdate(credit_card)
        post[:cvv2]     = credit_card.verification_value
      end

      def commit(action, money, parameters)
        response = parse(ssl_post(self.live_url, post_data(action, parameters)))

        Response.new(
          successful?(response),
          message_from(response),
          response,
          test: test_response?(response),
          authorization: authorization_from(response)
        )
      end

      def successful?(response)
        response[:status] == SUCCESS
      end

      def authorization_from(response)
        [response[:authnum], response[:transid]].compact.join(';')
      end

      def test_response?(response)
        !!(response[:transid] =~ /SimProxy/)
      end

      def message_from(response)
        successful?(response) ? SUCCESS_MESSAGE : response[:errorstring]
      end

      def parse(body)
        response = {}
        body.to_s.each_line do |l|
          key, value = l.split(':', 2)
          response[key.to_s.downcase.to_sym] = value.strip
        end
        response
      end

      def post_data(action, parameters = {})
        parameters[:request_type]     = TRANSACTIONS[action]
        parameters[:merchant_id]      = @options[:login]
        parameters[:password]         = @options[:password]

        parameters.reject { |_k, v| v.blank? }.collect { |key, value| "#{key.to_s.upcase}=#{CGI.escape(value.to_s)}" }.join('&')
      end
    end
  end
end
