package RPS::Import::Revolver;

use strict;

use Date::Calc qw(Days_in_Month Decode_Month);

use lib '/app/tools/common/lib';
use Common::Util;
use Common::Consts qw(%COUNTRY_CODE);
use Common::Country;

use lib '/app/tools/data_classes/lib';
use Client::Service;

use lib '/app/tools/rps/lib';
use RPS::File::Sale;
use RPS::Import::Importer;
use RPS::Import::ServiceMap;

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

my %field_map = (
    1 => {
        month          => 1,     # B
        year           => 2,     # C
        catalog_number => 3,     # D
        upc            => 4,     # E
        isrc           => 5,     # F
        artist         => 6,     # G
        album          => 7,     # H
        track          => 8,     # I
        country        => 10,    # K
        service        => 11,    # L
        units          => 12,    # M
        revenue        => 16,    # Q
    },

);

my %gServiceFormatMap = (
    'rhapsody - streams'                           => RPS::File::Sale::FORMAT_STREAM,
    'xbox music \(zune\)'                          => RPS::File::Sale::FORMAT_STREAM,
    'amazonmp3 cloud us'                           => RPS::File::Sale::FORMAT_STREAM,
    'amazonmp3 us'                                 => RPS::File::Sale::FORMAT_DOWNLOAD,
    'amazon cloud us'                              => RPS::File::Sale::FORMAT_DOWNLOAD,
    'itunes match (us|ca|mx)'                      => RPS::File::Sale::FORMAT_STREAM,
    'itunes (us|ca|mx)'                            => RPS::File::Sale::FORMAT_DOWNLOAD,
    'last.fm - (interactive|radio)'                => RPS::File::Sale::FORMAT_STREAM,
    'slacker - (basic|plus|premium) radio service' => RPS::File::Sale::FORMAT_STREAM,
    'zune - monthly zune pass 15 plus 10'          => RPS::File::Sale::FORMAT_STREAM,
    'amazon cloud us'                              => RPS::File::Sale::FORMAT_DOWNLOAD,
    'medianet digital'                             => RPS::File::Sale::FORMAT_STREAM,
    'amazonmp3'                                    => RPS::File::Sale::FORMAT_DOWNLOAD,
    'emusic (ca|us)'                               => RPS::File::Sale::FORMAT_DOWNLOAD,
);

#public methods

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

    my $lines    = $args{lines};
    my $version  = $args{file}->VersionNum();
    my $fileName = $args{file}->OrigFileName();
    my @sheets   = @{ $args{sheets} };

    return undef unless ($lines);

    my $linenum = 1;

    my $offsets = $field_map{$version};
    my %errors  = ();

    foreach my $line (@$lines) {
        my $countryName = lc $line->[ $offsets->{country} ];
        if ( $countryName eq 'country of sale' )    # skip header
        {
            $linenum++;
            next;
        }

        my $serviceName = $line->[ $offsets->{service} ];
        my $serviceID;

        if ($serviceName) {
            $serviceID = $self->getServiceID($serviceName) || $RPS::Import::ServiceMap::SERVICE_ALIASES{ lc $serviceName };
        }

        my $album = $line->[ $offsets->{album} ];
        my $track = $line->[ $offsets->{track} ];

        next if ( $countryName =~ m/^$/ && $album =~ m/^$/ && $track =~ m/^$/ );    # blank lines at eof

        my $countryCode;
        if ($countryName) {
            my $countryObj = Common::Country->Get($countryName);
            $countryCode = $countryObj->alpha2() if ($countryObj);

            if ( !$countryCode || '' eq $countryCode ) {
                $self->errstr( "Unknown country '$countryName' in line:" . $linenum );
                return undef;
            }
        } else {
            $self->errstr( "Missing country in line:" . $linenum );
            return undef;
        }

        if ( !$countryName || '' eq $countryName ) {
            $self->errstr( "Missing country in line:" . $linenum );
            return undef;
        }

        my ( $dateBegin, $dateEnd ) = $self->_getDates( $line->[ $offsets->{year} ], $line->[ $offsets->{month} ] );

        my $artist = $line->[ $offsets->{artist} ];

        my $catalog_number = $line->[ $offsets->{catalog_number} ];

        my $upc     = Common::Util::normalize_upc( $line->[ $offsets->{upc} ] );
        my $isrc    = Common::Util::normalize_isrc( $line->[ $offsets->{isrc} ] );
        my ($units) = $line->[ $offsets->{units} ];
        my $revenue = $line->[ $offsets->{revenue} ];

        my $product_type;
        my $format_type = $serviceName ? $self->_getFormatType($serviceName) : undef;

        if ($isrc) {
            $product_type = RPS::File::Sale::TYPE_TRACK;
        } else {
            $product_type = RPS::File::Sale::TYPE_ALBUM;
            if ( $track && '' ne $track ) {
                $album = $track;    # Use track name as album name (FB17250)
                undef $track;
            }
        }

        my $price = 0;

        $price = $revenue / $units if ( $units != 0 );

        if ( $units =~ /\d+/ && ( $track || $album ) && defined $price && $artist ) {
            if ( $price < 0 && $units > 0 )    # returns
            {
                $price = abs($price);
                $units *= -1;
            }

            if ( !$format_type && !$serviceName ) {

                # From Case 1967
                # If blank & product = track & PPU < .50 = DTeth.  If Blank + product = track + PPU > .51 = D.
                # If blank & product = album & PPU < 3 = DTeth.  If Blank + product = album + PPU > 3.01 = D.
                my $ppu = $price / $units;    # recall, price is _net_ revenue
                if ( $product_type eq RPS::File::Sale::TYPE_TRACK ) {
                    $format_type = ( abs($ppu) <= 0.50 ) ? RPS::File::Sale::FORMAT_TETHERED : RPS::File::Sale::FORMAT_DOWNLOAD;
                } elsif ( $product_type eq RPS::File::Sale::TYPE_ALBUM ) {
                    $format_type = ( abs($ppu) <= 3 ) ? RPS::File::Sale::FORMAT_TETHERED : RPS::File::Sale::FORMAT_DOWNLOAD;
                }

            }

            unless ( $countryCode or exists $errors{$countryName} ) {
                $self->errstr( 'unknown country:' . $countryName . " line:" . $linenum );
                print STDERR "country: '$countryName' line: $linenum\n";
                $errors{$countryName} = 1;
            }
            unless ( $dateBegin && $dateEnd ) {
                $self->errstr("couldn't get dates");
                print STDERR 'y,m: ', $line->[ $offsets->{year} ], ',', $line->[ $offsets->{month} ], "\n";
                return undef;
            }

            if ($serviceName) {

                unless ($serviceID) {
                    unless ( $errors{$serviceName} ) {
                        $self->errstr( 'Unknown service:' . $serviceName );
                        print STDERR "Unknown service: '$serviceName'\n";
                        $errors{$serviceName} = 1;
                    }
                }
            }
            my $sale = RPS::Import::SaleRec->new();

            $sale->serviceID($serviceID) if ($serviceName);
            $sale->dateBegin($dateBegin);
            $sale->dateEnd($dateEnd);
            $sale->upc($upc);
            $sale->isrc($isrc) if ( $product_type eq RPS::File::Sale::TYPE_TRACK );
            $sale->artistName($artist);
            $sale->albumName($album);
            $sale->trackName($track) if ( $product_type eq RPS::File::Sale::TYPE_TRACK );
            $sale->units($units);
            $sale->price($price);
            $sale->productType($product_type);
            $sale->formatType($format_type);
            $sale->lineNum($linenum);
            $sale->countryCode($countryCode);
            $sale->clientProductID($catalog_number);

            #$args{dumper}($sale);  ## for cmd-line testing
            $self->_insertSale( sale => $sale );
        }
        $linenum++;

    }

    return $linenum;
}

#
# Private methods
#

sub _getFormatType {
    my $self        = shift;
    my $serviceName = shift;
    my $_format;

    # New and improved format type rules (see Case 1967):
    #
    # If service name ends in
    #   streams = DS
    #   downloads = D
    #   basic = Dteth
    #   plays = DS
    #   MediaNet Digital - albums = D
    #   Mix and Burn = D
    #   Napster - ads = DS
    #   Napster - OTA = D
    #   Navio / gBox = D
    #   Passalong = D
    #   Pure Tracks = D
    #   Ruckus Network - university = DS
    #   SecuryCast Download = D
    #   Slacker - basic = DS
    #   Slacker - premium = DS
    #   T-Online = D
    #   Verizon = D
    #   Spring = D
    #   Sprint = D
    #   Rogers Wireless - subscriptions = DTeth
    #   Napster - download = D
    #   Rogers Wireless - subscriptions = D
    #   Virginmega.fr = D

    # If blank & product = track & PPU < .50 = DTeth.  If Blank + product = track + PPU > .51 = D.
    # If blank & product = album & PPU < 3 = DTeth.  If Blank + product = album + PPU > 3.01 = D.

    if ( $serviceName =~ /streams$/i )    # = DS
    {
        $_format = RPS::File::Sale::FORMAT_STREAM;
    } elsif ( $serviceName =~ /downloads$/i )    # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /basic$/i )        # = Dteth
    {
        $_format = RPS::File::Sale::FORMAT_TETHERED;
    } elsif ( $serviceName =~ /plays$/i )        # = DS
    {
        $_format = RPS::File::Sale::FORMAT_STREAM;
    } elsif ( $serviceName =~ /MediaNet Digital - albums$/i )    # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Mix and Burn$/i )                 # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Napster - ads$/i )                # = DS
    {
        $_format = RPS::File::Sale::FORMAT_STREAM;
    } elsif ( $serviceName =~ /Napster - OTA$/i )                # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Navio \/ gBox$/i )                # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Passalong$/i )                    # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Pure Tracks$/i )                  # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Ruckus Network - university$/i )    # = DS
    {
        $_format = RPS::File::Sale::FORMAT_STREAM;
    } elsif ( $serviceName =~ /SecuryCast Download$/i )            # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Slacker - basic$/i )                # = DS
    {
        $_format = RPS::File::Sale::FORMAT_STREAM;
    } elsif ( $serviceName =~ /Slacker - premium$/i )              # = DS
    {
        $_format = RPS::File::Sale::FORMAT_STREAM;
    } elsif ( $serviceName =~ /T-Online$/i )                       # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Verizon$/i )                        # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Spring$/i )                         # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Sprint/i )                          # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Rogers Wireless - subscriptions/i )    # = DTeth
    {
        $_format = RPS::File::Sale::FORMAT_TETHERED;
    } elsif ( $serviceName =~ /Napster - download/i )                 # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /Rogers Wireless - subscriptions/i )    # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    } elsif ( $serviceName =~ /virginmega.fr/i )                      # = D
    {
        $_format = RPS::File::Sale::FORMAT_DOWNLOAD;
    }

    # Old-style format lookup (FB17031).
    #
    #    foreach my $s (keys %gServiceFormatMap)
    #    {
    #        if( $serviceName =~ /$s/i )
    #        {
    #            $_format = $gServiceFormatMap{$s};
    #            last;
    #        }
    #    }

    return $_format;
}

sub _getDates {
    my $self  = shift;
    my $year  = shift;
    my $month = shift;

    my ( $dateBegin, $dateEnd );

    if ( !$year || !$month ) {
        return undef;
    }

    my %months = (
        "jan" => 1,
        "feb" => 2,
        "mar" => 3,
        "apr" => 4,
        "may" => 5,
        "jun" => 6,
        "jul" => 7,
        "aug" => 8,
        "sep" => 9,
        "oct" => 10,
        "nov" => 11,
        "dec" => 12
    );

    my $month_num;

    if ( ( lc $month ) =~ /(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/ ) {
        my $month_abbr = $1;

        $month_num = $months{$month_abbr};

        if ( !$month_num ) {
            return undef;
        }

        $dateBegin = sprintf( "%04d-%02d-%02d", $year, $month_num, 1 );
        $dateEnd = sprintf( "%04d-%02d-%02d", $year, $month_num, Days_in_Month( $year, $month_num ) );
    } elsif ( $month =~ /q(\d)/i ) {
        my $qtr = $1;

        if ( $qtr == 1 ) {
            $dateBegin = $year . "-01-01";
            $dateEnd = $year . "-03-" . Days_in_Month( $year, 3 );
        } elsif ( $qtr == 2 ) {
            $dateBegin = $year . "-04-01";
            $dateEnd = $year . "-06-" . Days_in_Month( $year, 6 );
        } elsif ( $qtr == 3 ) {
            $dateBegin = $year . "-07-01";
            $dateEnd = $year . "-09-" . Days_in_Month( $year, 9 );
        } elsif ( $qtr == 4 ) {
            $dateBegin = $year . "-10-01";
            $dateEnd = $year . "-12-" . Days_in_Month( $year, 12 );
        }

    }

    return ( $dateBegin, $dateEnd );
}

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