package RPS::Import::iTunesCloud;

use strict;

use Date::Calc qw(Days_in_Month);

use Data::Dumper;

use lib '/app/tools/common/lib';
use Common::Util;
use Common::Consts;

use lib '/app/tools/data_classes/lib';

use lib '/app/tools/rps/lib';
use RPS::File::Sale;
use RPS::DB::Item::MediaType;

use RPS::Import::Importer;
use base 'RPS::Import::Importer';

sub _fieldMap {
    my $self = shift;

    my %fieldMap = (
        1 => {
            labelName        => 'N',
            countryCode      => 'R',
            dateBegin        => 'A',
            dateEnd          => 'B',
            productType      => 'P',
            serviceProductID => 'K',
            clientProductID  => 'E',
            artistName       => 'L',
            upc              => 'C',
            albumName        => 'M',
            isrc             => 'D',
            trackName        => 'M',
            units            => 'F',
            currencyCode     => 'I',
        },
        # version 2 has the same title string as in version 1,
        # but footer is differ, see _unverifiedFieldMap
        2 => {
            labelName        => 'N',
            countryCode      => 'R',
            dateBegin        => 'A',
            dateEnd          => 'B',
            productType      => 'P',
            serviceProductID => 'K',
            clientProductID  => 'E',
            artistName       => 'L',
            upc              => 'C',
            albumName        => 'M',
            isrc             => 'D',
            trackName        => 'M',
            units            => 'F',
            currencyCode     => 'I',
        },
    );

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

sub _unverifiedFieldMap {
    my $self = shift;

    my %fieldMap = (
        1 => {
            # Footer
            footerLabel          => 'A',
            footerAmount         => 'B',
            countryOfSale        => 'A',
            partnerUnitTotal     => 'G',
            partnerShare         => 'H',
            publisherShare       => 'I',    # for older-style footer
        },
        # green bee was here :)
        # version 2 has an additionl column 'partnerShareCurrency'
        # will change version number on the fly in _preProcess sub
        2 => {
            # Footer
            footerLabel          => 'A',
            partnerShareCurrency => 'B',
            footerAmount         => 'C',
            countryOfSale        => 'A',
            partnerUnitTotal     => 'H',
            partnerShare         => 'I',
            publisherShare       => 'J',
        },
    );

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

sub _headerIdentifier { ( dateBegin => 'Start Date' ) }

sub formatType { return RPS::File::Sale::FORMAT_STREAM; }

sub productType {
    my $self = shift;

    my $productType = $self->_getByFieldName('productType') || return;

    if (   $productType eq 'H3'
        || $productType eq 'J3'
        || $productType eq 'V3'
        || $productType eq 'S3' ) {
        return RPS::File::Sale::TYPE_TRACK;
    } else {
        $self->fail("Unrecognized product type: $productType");
    }
}

sub mediaType {
    my $self = shift;

    my $productType = $self->_getByFieldName('productType') || return;

    if (   $productType eq 'H3'
        || $productType eq 'S3' ) {
        RPS::DB::Item::MediaType::kMediaTypeAudio;
    } elsif ( $productType eq 'J3'
        || $productType eq 'V3' ) {
        RPS::DB::Item::MediaType::kMediaTypeVideo;
    } else {
        $self->fail("Unrecognized product type: $productType");
    }
}

sub albumName {
    my $self = shift;

    if ( $self->productType() eq RPS::File::Sale::TYPE_ALBUM ) {
        return $self->_getByFieldName('albumName');
    }

    return undef;
}

sub trackName {
    my $self = shift;

    if ( $self->productType() eq RPS::File::Sale::TYPE_TRACK ) {
        return $self->_getByFieldName('trackName');
    }

    return undef;
}

sub unitPrice {
    my $self = shift;

    if ( ref( $self->{_price} ) eq 'HASH' ) {
        if ( $self->countryCode ) {
            if ( exists $self->{_price}{ $self->countryCode } ) {
                return $self->{_price}{ $self->countryCode };
            }
        }
    } else {
        return $self->{_price};
    }
}

sub _preProcess {
    my $self = shift;
    my %args = @_;

    Log->info("Starting _preProcess");
    $self->SUPER::_preProcess(%args);

    my $partnerShare;
    my $publisherShare;
    my $partnerUnits;
    my $foundSecondHeader;

    my $linenum = 1;

    # A country may appear more than once in the footer.  We'll keep
    # track of the total units and share by country.  After all footer
    # lines have been looked at, we'll then calculate a unit price
    # based on each country's aggregated unit and share information.
    #
    my %countryShareUnitMap;

    foreach my $line ( @{ $args{lines} } ) {
        $self->{line} = $line;

        my $units = $self->_getByFieldName('units');
        if ( $units =~ /^\d+$/ ) {
            $self->{_detailUnits} += $units;
        }

        my $footerLabel = $self->_getByFieldName('footerLabel');
        if ( $footerLabel =~ /^Cloud Partner Share$/ ) {
            $partnerShare = $self->_getByFieldName('footerAmount');
        }
        elsif ( $footerLabel =~ /^Cloud Publisher Share$/ ) {
            $publisherShare = $self->_getByFieldName('footerAmount');
        }
        elsif ( $footerLabel =~ /^Partner Converted Unit Total$/ ) {
            $partnerUnits = $self->_getByFieldName('footerAmount');
        }
        # The 'Country of Sale' label is only present if we're processing an iTunes file
        # with a separate footer section with a header row (FB15789, FB17046).
        elsif ( $footerLabel =~ /^Country Of Sale$/ ) {

            # check for version 2 compatibility
            my $isFooterAmount = $self->_getByFieldName('footerAmount');
            unless ( $isFooterAmount =~ /^Total iTunes Plays$/i ) {
                $self->{versionNum} = 2;
            }

            $foundSecondHeader = 1;
            $linenum++;
            next;
        }

        if ( $foundSecondHeader == 1 ) {
            my $_partnerShare = $self->_getByFieldName('partnerShare');
            my $_partnerUnits = $self->_getByFieldName('partnerUnitTotal');
            my $countryOfSale = $self->_getByFieldName('countryOfSale');

            if ( $countryOfSale =~ /^\w{1,2}$/ ) {
                $self->fail("Line $linenum: Unable to determine unit price")
                  unless ( $_partnerShare && $_partnerUnits );

                # Aggregate units and share by country
                #
                $countryShareUnitMap{$countryOfSale}{units} += $_partnerUnits;
                $countryShareUnitMap{$countryOfSale}{share} += $_partnerShare;

            }

            $partnerUnits += $_partnerUnits;
        }

        $linenum++;
    }

    # Calculate each country's unit rate
    #
    foreach my $countryOfSale ( keys %countryShareUnitMap ) {
        my $_partnerUnits = $countryShareUnitMap{$countryOfSale}{units};
        my $_partnerShare = $countryShareUnitMap{$countryOfSale}{share};
        $self->{_price}{$countryOfSale} = $_partnerShare / $_partnerUnits;
    }

    # We'll compare the units from the footer with the
    # units read from the detail lines (see _postProcess).
    #
    $self->{_partnerUnits} = $partnerUnits;

    # If we did not find a footer with the 'Country Of Sale' column in the
    # header, then we'll store the price information as a scalar instead
    # of a country-based hash table.
    #
    if ( !$foundSecondHeader ) {
        my $price = ( $partnerShare + $publisherShare ) / $partnerUnits;
        $self->{_price} = $price;
    }

}

sub _postProcess {
    my $self = shift;
    my %args = @_;

    Log->info("Starting _postProcess");
    $self->SUPER::_postProcess(%args);

    return if $self->_version == 2;

    # Just making sure that the unit total we came up with matches what's in the footer.
    my $footerTotal = $self->{_partnerUnits};
    my $detailTotal = $self->{_detailUnits};

    if ( $footerTotal != $detailTotal ) {
        $self->errstr("Unit detail total ($detailTotal) differs from unit total listed in footer ($footerTotal)");
        return undef;
    }
}

sub _isValidSaleRecord {
    my $self = shift;

    return ( defined( $self->units )
          && ( $self->trackName || $self->albumName )
          && ( $self->labelName || $self->productType || $self->countryCode ) );
}

###
1;    # Play nicely.
###
