package BookPub::Import::Importer::AmazonTax;

use strict;

use lib '/app/tools/bookpub/lib';
use base 'BookPub::Import::Importer';

use Date::Calc qw( Add_Delta_YM );

sub _headerIdentifier { ( serviceProductID => 'asin' ) }

# map version num to the field order
sub _fieldMap {
    my $self = shift;

    my %fieldMap = (
        33 => {
            serviceProductID       => 'F',
            currencyCode           => 'AA',
            countryCode            => 'X',
            rState                 => 'W',
            rPostalCode            => 'Y',
            dateBegin              => 'D',
            rIsbn13                => 'E',
            rTitle                 => 'G',
            rAuthor                => 'H',
            rUnits                 => 'I',
            rListPrice             => 'N',
            rListPriceCurrency     => 'O',
            rPurchasePrice         => 'P',
            rPurchasePriceCurrency => 'Q',
            rRevenue               => 'Z',
        },
        34 => {
            serviceProductID       => 'F',
            currencyCode           => 'AA',
            countryCode            => 'X',
            rState                 => 'W',
            rPostalCode            => 'Y',
            dateBegin              => 'D',
            rIsbn13                => 'E',
            rTitle                 => 'G',
            rAuthor                => 'H',
            rUnits                 => 'I',
            rListPrice             => 'N',
            rListPriceCurrency     => 'O',
            rPurchasePrice         => 'R',
            rPurchasePriceCurrency => 'S',
            rRevenue               => 'AK',
            conversionRate         => 'AH1',
        },
        37 => {
            purchaseType           => 'BG',
            serviceProductID       => 'G',
            currencyCode           => 'BD',
            countryCode            => 'Y',
            rState                 => 'W',
            rPostalCode            => 'X',
            dateBegin              => 'D',
            rIsbn13                => 'F',
            rTitle                 => 'H',
            rAuthor                => 'I',
            rUnits                 => 'K',
            rListPrice             => 'M',
            rListPriceCurrency     => 'N',
            rPurchasePrice         => 'O',
            rPurchasePriceCurrency => 'P',
            rTaxAmount             => 'BE',
            rRevenue               => 'BC',
        },
        58 => {
            dateBegin              => 'D',
            rPurchaseType          => 'BI',
            purchaseType           => 'BI',
            rProductType           => 'J',
            rAuthor                => 'I',
            rTitle                 => 'H',
            rIsbn13                => 'F',
            rState                 => 'W',
            rPostalCode            => 'X',
            countryCode            => 'Y',
            serviceProductID       => 'G',
            rUnits                 => 'K',
            rListPrice             => 'M',
            rListPriceCurrency     => 'N',
            rPurchasePrice         => 'O',
            rPurchasePriceCurrency => 'P',
            rRevenue               => 'BE',
            currencyCode           => 'BF',
            rTaxAmount             => 'BG',
            rDuration              => 'BJ',
        },
        78 => {
            dateBegin              => 'D',
            rPurchaseType          => 'BO',
            purchaseType           => 'BO',
            rProductType           => 'J',
            rAuthor                => 'I',
            rTitle                 => 'H',
            rIsbn13                => 'F',
            rState                 => 'AH',
            rPostalCode            => 'X',
            countryCode            => 'Y',
            serviceProductID       => 'G',
            rUnits                 => 'K',
            rListPrice             => 'M',
            rListPriceCurrency     => 'N',
            rPurchasePrice         => 'O',
            rPurchasePriceCurrency => 'P',
            rRevenue               => 'BK',
            currencyCode           => 'BL',
            rTaxAmount             => 'BM',
            rDuration              => 'BP',
        },
    );

    return $fieldMap{ $self->_version() };
}

sub _unverifiedFieldMap {
    my $self = shift;

    my %fieldMap = (
        33 => {
            transactionStatus => 'J',
            transactionType   => 'K',
            rListPriceWithTax => 'L',
        },
        34 => {
            transactionStatus => 'J',
            transactionType   => 'K',
            rListPriceWithTax => 'L',
            conversionRate2   => 'AH2',
        },
        37 => {
            transactionStatus => 'L',
            transactionType   => 'R',
            taxCurrency       => 'BF',
        },
        58 => {
            transactionStatus => 'L',
            transactionType   => 'R',
            taxCurrency       => 'BH',
        },
        78 => {
            transactionStatus => 'L',
            transactionType   => 'R',
            taxCurrency       => 'BN',
        },
    );

    return $fieldMap{ $self->_version() };
}

sub _useIsSaleRec              { 1 }
sub _autoParseTitleAndSubtitle { 1 }
sub priceType                  { 'agency' }
sub productType                { BookPub::DB::Item::Sale::kProductTypeEBook }

sub rServiceName {
    return BookPub::Tracker::Service::GetDefaultServiceName(
        service_id => shift->serviceID
    );
}

sub rUnits {
    my $self            = shift;
    my $units           = $self->_getByFieldName('rUnits');
    my $transactionType = $self->_getByFieldName('transactionType');

    if ( uc($transactionType) eq 'REFUND' && $units > 0 ) {
        $units *= -1;
    }

    return $units;
}

sub rState {
    my $self  = shift;
    my $state = $self->_getByFieldName('rState');
    $state =~ s/\.//g;
    return 'washington' if $state =~ /^washinton$/i;

    return $state;
}

sub purchaseType {
    my $self = shift;
    if ( $self->_getByFieldName('purchaseType') ) {
        my $purchaseType = $self->_getByFieldName('purchaseType');
        if ( uc($purchaseType) eq "CHECKOUT" || uc($purchaseType) eq "EXTENSION" ) {
            return BookPub::DB::Item::Sale::kPurchaseTypeLoan;
        } elsif ( uc($purchaseType) eq "PURCHASE" ) {
            return BookPub::DB::Item::Sale::kPurchaseTypeDownload;
        } else {
            $self->fail("Could not determine purchase type from $purchaseType");
        }
    } else {
        return BookPub::DB::Item::Sale::kPurchaseTypeDownload;
    }
}

# conversionRate is plucked from the header, but the header line moves around.  This
# is handled in the header rules with 'match_on_any_row', but we need to check at
# least two cells here.
sub conversionRate {
    my $self = shift;

    # Not every version that is supported here uses conversionRate,
    # so let's test for that first.
    if ( defined $self->_getByFieldName('conversionRate') ) {
        my $rate  = $self->_getByFieldName('conversionRate');
        my $rate2 = $self->_getByFieldName('conversionRate2');
        my $useThisRate;

        if ( defined $rate ) {
            $useThisRate = $rate;
        } elsif ( defined $rate2 ) {
            $useThisRate = $rate2;
        } else {
            $self->fail("Conversion rate was not in the cells expected");
        }

        if ( $useThisRate =~ /sale amount canadian \$ \((.+)\)/i ) {
            $useThisRate = $1;
            return $useThisRate;
        } else {
            $self->fail("Unable to identify conversion rate in header: $useThisRate");
        }
    }
    return undef;
}

sub rRevenue {
    my $self    = shift;
    my $revenue = $self->_getByFieldName('rRevenue');

    if ( !$revenue ) {
        $revenue = 0;
    } else {
        my $transactionType = $self->_getByFieldName('transactionType');

        if ( uc($transactionType) eq 'REFUND' && $revenue > 0 ) {
            $revenue *= -1;
        }

    }

    return $revenue;
}

sub rListPriceCurrency {
    my $self          = shift;
    my $priceCurrency = $self->_getByFieldName('rListPriceCurrency');
    my $currencyCode  = $self->_getByFieldName('currencyCode');

    # For the clients that require list price currency to match the revenue currency.
    # If we have a conversion rate, then we'll just switch this to the revenue currrency code.
    if ( $self->listPriceRequired && $priceCurrency ne $currencyCode ) {
        if ( $self->conversionRate() ) {
            $priceCurrency = $currencyCode;
        } else {

            # Otherwise, we'll try the purchase price.
            $priceCurrency = $self->_getByFieldName('rPurchasePriceCurrency');
        }
    }

    return $priceCurrency;
}

sub rListPrice {
    my $self             = shift;
    my $priceCurrency    = $self->_getByFieldName('rListPriceCurrency');
    my $purchaseCurrency = $self->_getByFieldName('rPurchasePriceCurrency');
    my $currencyCode     = $self->_getByFieldName('currencyCode');
    my $listPrice        = $self->_getByFieldName('rListPrice');

    # For the clients that require list price currency to match the revenue currency.
    # First, check for a conversion rate.
    if ( $self->listPriceRequired && $priceCurrency ne $currencyCode ) {
        if ( $self->conversionRate() ) {
            $listPrice /= $self->conversionRate();
        } elsif ( $purchaseCurrency eq $currencyCode ) {

            # If there's no conversion rate, the best we can do is to default to the purchase price.
            $listPrice = $self->_getByFieldName('rPurchasePrice');
        } else {
            $self->fail("Unable to convert list price to revenue currency");
        }
    }

    return $listPrice;
}

sub rTaxAmount {
    my $self = shift;
    my $tax;
    if ( defined $self->_getByFieldName('rTaxAmount') && $self->_version() != 33 ) {
        my $tax = $self->_getByFieldName('rTaxAmount');
        if ($tax) {
            my $taxCurrency   = $self->_getByFieldName('taxCurrency');
            my $priceCurrency = $self->rListPriceCurrency();
            if ( $taxCurrency ne $priceCurrency ) {

                # For now, we're just going to error out if this happens.
                # We may have to come up with some clever way to convert this if it comes up a lot.
                $self->fail("Tax currency does not match list price currency");
            }
        }
        return $tax;
    } else {
        my $price        = $self->_getByFieldName('rListPrice');
        my $priceWithTax = $self->_getByFieldName('rListPriceWithTax');
        if ( $price && $priceWithTax ) {
            my $revenue = $self->_getByFieldName('rRevenue');
            my $units   = $self->rUnits();

            $tax = $units * ( $priceWithTax - $price );
            $tax = -1 * abs($tax) if ( $revenue < 0 );
            return $tax;
        }
    }
}

sub _getDateBegin {
    my $self = shift;
    my $date = $self->_getByFieldName('dateBegin') || return;

    my %monthAbbrToNumber;
    $monthAbbrToNumber{"JAN"} = 1;
    $monthAbbrToNumber{"FEB"} = 2;
    $monthAbbrToNumber{"MAR"} = 3;
    $monthAbbrToNumber{"APR"} = 4;
    $monthAbbrToNumber{"MAY"} = 5;
    $monthAbbrToNumber{"JUN"} = 6;
    $monthAbbrToNumber{"JUL"} = 7;
    $monthAbbrToNumber{"AUG"} = 8;
    $monthAbbrToNumber{"SEP"} = 9;
    $monthAbbrToNumber{"OCT"} = 10;
    $monthAbbrToNumber{"NOV"} = 11;
    $monthAbbrToNumber{"DEC"} = 12;

    # Date format: 16-DEC-2012 14:16:18
    #
    if ( $date =~ /(\d{2})-(\w{3})-(\d{4})/ ) {
        my $day       = $1;
        my $monthAbbr = uc($2);
        my $year      = $3;

        my $month = $monthAbbrToNumber{$monthAbbr};

        $date = $year . "-" . $month . "-" . $day;
    } elsif ( $date =~ /(\d{2})\/(\d{2})\/(\d{4})/ ) {

        # Another date format: 31/03/2013 03:03:20 PM
        #
        $date = $3 . "-" . $2 . "-" . $1;

    } elsif ( $date =~ /(\w{3}) (\d{2}) \d{2}:\d{2}:\d{2} \w{3} (\d{4})/ ) {

        # New date format: Mon Jul 01 20:05:57 PDT 2013
        #
        my $day       = $2;
        my $monthAbbr = uc($1);
        my $year      = $3;

        my $month = $monthAbbrToNumber{$monthAbbr};

        $date = $year . "-" . $month . "-" . $day;
    }

    return $date;
}

sub rReturns {
    my $self = shift;

    my $transactionType = $self->_getByFieldName('transactionType') || 0;
    my $rUnits          = $self->_getByFieldName('rUnits')          || 0;
    if ( $transactionType =~ /^refund$/i ) {
        return $rUnits;
    }

    return 0;
}

sub rSales {
    my $self = shift;

    my $transactionType = $self->_getByFieldName('transactionType') || 0;
    my $rUnits          = $self->_getByFieldName('rUnits')          || 0;
    if ( $transactionType =~ /^digital_order$/i ) {
        return $rUnits;
    }

    return 0;
}

sub countryCode {
    my $self = shift;

    my $code = $self->_getByFieldName("countryCode") || "";
    my $filename = $self->filename() || "";

    return $code if $code;
    return "US"  if ($filename =~ /^MXARQ/);

    $self->fail("Could not determine country code from '$code' or filename: $filename");
}

sub isFree {
    my $self = shift;

    return !$self->rRevenue && $self->rUnits ? 'Y' : 'N';
}

sub _isSaleRec {
    my $self = shift;

    my $transactionStatus = uc( $self->_getByFieldName('transactionStatus') );
    my $revenue           = $self->SUPER::revenue();

    # We're going to skip some of the lines if they have a certain status.
    if ( ( $transactionStatus eq "REFUNDED_NOT_RECEIVED" || $transactionStatus eq "FULFILLED_NOT_PAID" ) && $revenue == 0 ) {
        return 0;
    }

    return $self->SUPER::_isSaleRec();
}

1;
