package Business::OnlinePayment::FirstDataGlobalGateway;
use base qw( Business::OnlinePayment );

use warnings;
use strict;
use Data::Dumper;
use Business::CreditCard;
use SOAP::Lite +trace => 'all';
#SOAP::Lite->import(+trace=>'debug');

our $VERSION = '0.01';
$VERSION = eval $VERSION; # modperlstyle: convert the string into a number

our @alpha = ( 'a'..'z', 'A'..'Z', '0'..'9' );

sub _info {
  {
    'info_compat'       => '0.01',
    'gateway_name'      => 'First Data Global Gateway e4',
    'gateway_url'       => 'https://www.firstdata.com/en_us/products/merchants/ecommerce/online-payment-processing.html',
    'module_version'    => $VERSION,
    'supported_types'   => [ 'CC' ], #, 'ECHECK' ],
    #'token_support'     => 1,
    #'test_transaction'  => 1,

    'supported_actions' => [ 'Normal Authorization',
                             #'Credit',
                           ],
  };
}

sub set_defaults {
    my $self = shift;
    #my %opts = @_;

    #$self->build_subs(qw( order_number avs_code cvv2_response
    #                      response_page response_code response_headers
    #                 ));

    $self->build_subs(qw( avs_code ));

}

sub map_fields {
    my($self) = @_;

    my %content = $self->content();

    # TYPE MAP
    my %types = ( 'visa'               => 'CC',
                  'mastercard'         => 'CC',
                  'american express'   => 'CC',
                  'discover'           => 'CC',
                  'check'              => 'ECHECK',
                );
    $content{'type'} = $types{lc($content{'type'})} || $content{'type'};
    $self->transaction_type($content{'type'});
    
    # ACTION MAP 
    my $action = lc($content{'action'});
    my %actions =
      ( 'normal authorization' => '00', # Purchase
        'authorization_only'   => '01', # 
        'post authorization'   => '02', # Pre-Authorization Completion
        # '' => '03', # Forced Post
        'credit'               => '04', # Refund
        # '' => '05', # Pre-Authorization Only
        'void'                 => '13', # Void
        #'reverse authorization' => '',

        # '' => '07', # PayPal Order
        # '' => '32', # Tagged Pre-Authorization Completion
        # '' => '33', # Tagged Void
        # '' => '34', # Tagged Refund
        # '' => '83', # CashOut (ValueLink, v9 or higher end point only)
        # '' => '85', # Activation (ValueLink, v9 or higher end point only)
        # '' => '86', # Balance Inquiry (ValueLink, v9 or higher end point only)
        # '' => '88', # Reload (ValueLink, v9 or higher end point only)
        # '' => '89', # Deactivation (ValueLink, v9 or higher end point only)
      );

    $content{'action'} = $actions{$action} || $action;

    # stuff it back into %content
    $self->content(%content);

}

sub remap_fields {
    my($self,%map) = @_;

    my %content = $self->content();
    foreach(keys %map) {
        $content{$map{$_}} = $content{$_};
    }
    $self->content(%content);
}

sub submit {
  my($self) = @_;

  $self->map_fields;

  $self->remap_fields(
        'login'             => 'ExactID',
        'password'          => 'Password',

        'action'            => 'TransactionType',

        'amount'            => 'DollarAmount',
        'currency'          => 'Currency',
        'card_number'       => 'Card_Number',
        'track1'            => 'Track1',
        'track2'            => 'Track2',
        'expiration'        => 'Expiry_Date',
        'name'              => 'CardHoldersName',
        'cvv2'              => 'VerificationStr2',

        'authorization'     => 'Authorization_Num',
        'order_number'      => 'Reference_No',

        'zip'               => 'ZipCode',
        'tax'               => 'Tax1Amount',
        'customer_id'       => 'Customer_Ref',
        'customer_ip'       => 'Client_IP',
        'email'             => 'Client_Email',

        #account_type      => 'accountType',

  );

  my %content = $self->content();

  #$content{'mop'} = $mop{ cardtype($content{creditCardNum}) }
  #  if $content{'type'} eq 'CC';

  #if ( $self->test_transaction ) {
  #  $content{agentCode} = 'TEST88';
  #  $content{password}  = 'TEST88';
  #}

  $content{Expiry_Date} =~ s/\///;

  $content{country} ||= 'US';

  $content{VerificationStr1} =
    join('|', map $content{$_}, qw( address zip city state country ));
  $content{VerificationStr1} .= '|'. $content{'phone'}
    if $content{'type'} eq 'ECHECK';

  $content{CVD_Presence_Ind} = '1' if length($content{VerificationStr2});

  $content{'Reference_No'} ||= join('', map $alpha[int(rand(62))], (1..20) );

  #XXX this should be exposed as a standard B:OP field, not just recurring/no
  if ( defined($content{'recurring_billing'})
       && $content{'recurring_billing'} =~ /^[y1]/ ) {
    $content{'Ecommerce_Flag'} = '2';
  } else {
    #$content{'Ecommerce_Flag'} = '1'; 7?  if there's an IP?
  }

  my $base_uri;
  if ( $self->test_transaction ) {
    $base_uri =
      'https://api.demo.globalgatewaye4.firstdata.com/transaction';
  } else {
    $base_uri =
      'https://api.globalgatewaye4.firstdata.com/vplug-in/transaction';
  }

  my $proxy = "$base_uri/v11";
  my $uri = "$base_uri/rpc-enc";

  my %transaction = map { $_ => $content{$_} } (qw(
    ExactID Password Transaction_Type DollarAmount Card_Number Transaction_Tag
    Track1 Track2 Authorization_Num Expiry_Date CardHoldersName
    VerificationStr1 VerificationStr2 CVD_Presence_Ind Reference_No ZipCode
    Tax1Amount Tax1Number Tax2Amount Tax2Number Customer_Ref Reference_3
    Language Client_IP Client_Email user_name Currency PartialRedemption
    CAVV XID Ecommerce_Flag
 ));
   #TransarmorToken CardType EAN VirtualCard CardCost FraudSuspected
   #CheckNumber CheckType BankAccountNumber BankRoutingNumber CustomerName
   #CustomerIDType CustomerID

  #my @opts = map { SOAP::Data->name($_)->value( $data{$_} ) }
  #             keys %data;

  my $result = SOAP::Lite
                 ->proxy($proxy)

                 ->default_ns($base_uri)
                 ->uri($uri)

                 ->on_action( sub { join '/', @_ } )
                 #->on_action( sub { join '', @_ } )
                 #->on_action(sub { qq("$_[0]") }) #? https://firstdata.zendesk.com/entries/407569-First-Data-Global-Gateway-e4-Web-Service-API-Sample-Code-Perl
                 ->autotype(0)

                 ->readable(1)

                 ->ns($uri,'q1')
                 ->SendAndCommit( SOAP::Data->name('Transaction')->value( \%transaction ) )

                 ->result();

  die Dumper($result);

  die Dumper($result->result) if $result->fault;
  #die $result->fault->faultstring if $result->fault;

  die Dumper($result);

  #$self->is_success
  #$self->authorization
  #$self->avs_code
  #$self->error_message
  #$self->result_code
  ##$self->failure_status

}

1;

__END__

=head1 NAME

Business::OnlinePayment::FirstDataGlobalGateway - First Data Global Gateway e4 backend for Business::OnlinePayment

=head1 SYNOPSIS

  use Business::OnlinePayment;

  my $tx =
    new Business::OnlinePayment( 'FirstDataGlobalGateway' );

  $tx->content(
      login          => 'TEST88', # ExactID
      password       => 'TEST88', #password 

      type           => 'CC',
      action         => 'Normal Authorization',
      amount         => '1.00',

      first_name     => 'Tofu',
      last_name      => 'Beast',
      address        => '123 Anystreet',
      city           => 'Anywhere',
      state          => 'UT',
      zip            => '84058',

      card_number    => '4111111111111111',
      expiration     => '09/20',
      cvv2           => '124',

      #optional
      customer_ip    => '1.2.3.4',
  );
  $tx->submit();

  if($tx->is_success()) {
      print "Card processed successfully: ".$tx->authorization."\n";
  } else {
      print "Card was rejected: ".$tx->error_message."\n";
  }

=head1 SUPPORTED TRANSACTION TYPES

=head2 CC, Visa, MasterCard, American Express, Discover

Content required: type, login, action, amount, card_number, expiration.

=head2 (NOT YET) Check

Content required: type, login, action, amount, name, account_number, routing_code.

=head1 DESCRIPTION

For detailed information see L<Business::OnlinePayment>.

=head1 METHODS AND FUNCTIONS

See L<Business::OnlinePayment> for the complete list. The following methods either override the methods in L<Business::OnlinePayment> or provide additional functions.  

=head2 result_code

Returns the response error code.

=head2 error_message

Returns the response error number.

=head2 action

The following actions are valid

  Normal Authorization
  Authorization Only
  Post Authorization
  Credit
  Void

=head1 COMPATIBILITY

Business::OnlinePayment::FirstDataGlobalGateway uses the v11 version of the API
at this time.

=head1 AUTHORS

Ivan Kohler <ivan-firstdataglobalgateway@freeside.biz>

=head1 SEE ALSO

perl(1). L<Business::OnlinePayment>.

=cut

