package RPS::Import::KochDigital;

use strict;
use warnings;

use Date::Calc qw(Days_in_Month);
use Math::BigFloat;

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

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 base 'RPS::Import::Importer';

my %indexes = map { lc $_ => -1 } (
    'Album ID / Item #',
    'Album / Track Artist',
    'Album / Track Title',
    'Digital Provider',
    'Disc',
    'Dollars',
    'Format',
    'Units',
    'UPC / ISRC #',
);

# Insert aliases to the above in here:
my %aliases = map lc, (

    #'Foo Bar'  => 'Original Name',
    'Album  / Track Title' => 'Album / Track Title',
    'service_product_id'   => 'Album ID / Item #',
    'artist'               => 'Album / Track Artist',
    'format'               => 'Format',
    'prodcode'             => 'UPC / ISRC #',
    'service'              => 'Digital Provider',
    'title'                => 'Album / Track Title',
    'units'                => 'Units',
    'price'                => 'Dollars',
);

my %format_map = (
    'track ***'                         => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_DOWNLOAD ],
    'track download'                    => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_DOWNLOAD ],
    'track teth download'               => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_TETHERED ],
    'track stream'                      => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_STREAM ],
    'track ringtone'                    => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_RINGTONE ],
    'track background'                  => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_BACKGROUNDMUSIC ],
    'album download'                    => [ RPS::File::Sale::TYPE_ALBUM, RPS::File::Sale::FORMAT_DOWNLOAD ],
    'track non drm upgrade track'       => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_DOWNLOADUPGRADE ],
    'album high quality song'           => [ RPS::File::Sale::TYPE_ALBUM, RPS::File::Sale::FORMAT_DOWNLOADPREMIUM ],
    'track high quality song'           => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_DOWNLOADPREMIUM ],
    'album high quality playlist/album' => [ RPS::File::Sale::TYPE_ALBUM, RPS::File::Sale::FORMAT_DOWNLOADPREMIUM ],
    'album non drm upgrade album'       => [ RPS::File::Sale::TYPE_ALBUM, RPS::File::Sale::FORMAT_DOWNLOADUPGRADE ],
    'track song'                        => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_DOWNLOAD ],
    'track download-subscription'       => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_VPD ],
    'track burn'                        => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_DOWNLOAD ],
    'album download-subscription'       => [ RPS::File::Sale::TYPE_ALBUM, RPS::File::Sale::FORMAT_VPD ],
    'album playlist upgrade'            => [ RPS::File::Sale::TYPE_ALBUM, RPS::File::Sale::FORMAT_DOWNLOADUPGRADE ],
    'track video teth downl'            => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_TETHERED ],
    'track audio ad support/stream'     => [ RPS::File::Sale::TYPE_TRACK, RPS::File::Sale::FORMAT_STREAM ],
);

#
# This map is no longer used.  Calling the function getServiceID instead.
my %service_map = map lc,
  (
    AltNet         => Client::Service::DSP_ALTNET,
    BuyMusic       => Client::Service::DSP_BUYMUSIC,
    eMusic         => Client::Service::DSP_EMUSIC,
    iTunes         => Client::Service::DSP_ITUNES,
    'Liquid Audio' => Client::Service::DSP_LIQUIDAUDIO,
    MusicMatch     => Client::Service::DSP_MUSICMATCH,
    MusicNet       => Client::Service::DSP_MEDIANET,
    MusicNow       => Client::Service::DSP_MUSICNOW,
    Napster        => Client::Service::DSP_NAPSTER,
    Real           => Client::Service::DSP_REAL,
    "musicgiant"   => Client::Service::DSP_MUSICGIANTS,
    "hdtracks"     => Client::Service::DSP_HDTRACKS,
  );

my %format_errors;

#public methods

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

    my $fileObj  = $args{file};
    my $fileName = $fileObj->OrigFileName;
    ##my $fileName = $args{OrigFileName}; ## for cmd-line testing

    my $lines = $args{lines};

    my $linenum     = 1;
    my $headerFound = 0;

    my $fileDate;

    while ( my $line = shift @$lines ) {
        my @elements = map { Common::Util::trimspaces($_) } @$line;
        my $elementnum = 0;
        for my $element (@elements) {
            my $e = lc $element;

            # We can also find the date through regex,
            # but it seems to make the import run a lot slower.
            #if ($e =~ m/^fiscal period:/)
            if ( ( $linenum == 5 ) && ( $elementnum == 2 ) ) {
                $fileDate = $e;
            }

            if ( exists $aliases{$e} ) {
                $e = $aliases{$e};
            }
            if ( exists $indexes{$e} ) {
                $indexes{$e} = $elementnum;
                ++$headerFound;
            }
        }

        continue { $elementnum++; }
    } continue {
        $linenum++;

        if ($headerFound) {
            my $keyCount = scalar keys %indexes;
            if ( $headerFound != $keyCount ) {
                warn "Not all headers found, $headerFound != $keyCount:\n",
                  "Not found: ",
                  join( ', ', grep { $indexes{$_} < 0 } keys %indexes );
            }

            last;
        }
    }

    #
    # First we'll check for the date in the file name
    my ( $dateBegin, $dateEnd ) = $self->_getDatesFromFileName($fileName);

    #
    # If there's no date in the file name, we'll look in the file
    unless ( defined $dateBegin && defined $dateEnd ) {
        ( $dateBegin, $dateEnd ) = $self->_getDatesFromFile($fileDate);
    }

    #
    # If there's no date in the file name or file, then game over, man.
    unless ( defined $dateBegin && defined $dateEnd ) {
        print STDERR "Couldn't get dates from: " . $fileName . "\n";
        $self->errstr( "couldn't get dates from: " . $fileName );
        return undef;
    }

    foreach my $line (@$lines) {
        my $artist           = $line->[ $indexes{ $aliases{artist} } ];
        my $format           = $line->[ $indexes{ $aliases{format} } ];
        my $price            = $line->[ $indexes{ $aliases{price} } ];
        my $prodcode         = $line->[ $indexes{ $aliases{prodcode} } ];
        my $serviceName      = $line->[ $indexes{ $aliases{service} } ];
        my $title            = $line->[ $indexes{ $aliases{title} } ];
        my $units            = $line->[ $indexes{ $aliases{units} } ];
        my $serviceProductID = $line->[ $indexes{ $aliases{service_product_id} } ];

        unless ( $artist && $serviceName && $title && $units ) {
            next;
        }

        my $prodtype = $format_map{ lc $format };

        if ( !$prodtype && !$format_errors{$format} ) {
            $self->errstr("Unknown format '$format'");
            print STDERR "Uknown format: '$format\n'";
            $format_errors{$format} = 1;
            next;

            #return;
        } elsif ( !$prodtype ) {
            next;
        }

        ( $prodtype, $format ) = @{$prodtype};

        my $service = $self->_get_service_id($serviceName);

        unless ($service) {

            #print STDERR "Using service map: X".lc($serviceName)."X\n";
            $service = $service_map{ lc $serviceName };
        }

        #$service = $service_map{ lc $service };
        unless ($service) {
            $self->errstr("Unknown service '$serviceName'");
            return;
        }

        # Figure out if this is whole album info, or just single track info:
        my ( $album, $upc );
        my ( $track, $trackNum, $isrc );
        if ( $prodtype eq RPS::File::Sale::TYPE_TRACK ) {
            ( $trackNum, $track ) = $title =~ /^\s*Track:?\s*(\d+)\s*[:-]\s*(.*)/;
            $isrc = $prodcode;
        } elsif ( $prodtype eq RPS::File::Sale::TYPE_ALBUM ) {
            $album = $title;
            $upc   = $prodcode;
        } else {
            $self->errstr("Unknown product type '$prodtype'");
            return;
        }

        if ( 0 != $units ) {
            $price = Math::BigFloat->new($price);
        } else {
            $price = 0;
        }

        my $sale = RPS::Import::SaleRec->new();

        $sale->albumName($album) if ($album);
        $sale->artistName($artist);

        # averagePrice channel clientProductID
        # configuration conversionRate countryCode
        # currencyCode
        $sale->dateBegin($dateBegin);
        $sale->dateEnd($dateEnd);
        $sale->formatType($format);

        # free importStatus
        $sale->isrc($isrc) if ($isrc);

        # labelName
        $sale->lineNum($linenum);

        # outlet payoutType
        $sale->price( $price / $units );

        # priceLevel priceType
        $sale->productType($prodtype);

        # retail returns returnsRevenue
        # sales salesRevenue
        $sale->serviceID($service);

        # serviceProductID totalRevenue
        $sale->trackName($track)   if ($track);
        $sale->trackNum($trackNum) if ($trackNum);
        $sale->units($units);
        $sale->upc($upc) if ($upc);
        $sale->serviceProductID($serviceProductID);

        # wholesaleRate

        if ( $serviceName =~ /Canada/ ) {
            $sale->countryCode('CA');
        } else {
            $sale->countryCode('US');
        }

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

    return $linenum;
}

#
# Private methods
#

my %month_map = (
    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 = '(?:' . join( '|', sort keys %month_map ) . ')';
my $YY = qr/[0-9]{2}/;

sub _getDatesFromFileName {
    my $self  = shift;
    my $fname = shift;
    return unless ( $fname =~ m/^BN($MONTH)($YY)digital/ );

    my $month = $month_map{$1};
    my $year  = 2000 + $2;

    my $month_end = Days_in_Month( $year, $month );

    my $format    = '%4d-%02d-%02d';
    my $beginDate = sprintf( $format, $year, $month, 1 );
    my $endDate   = sprintf( $format, $year, $month, $month_end );

    return ( $beginDate, $endDate );
}

sub _getDatesFromFile {

    # This is what get's passed in:
    # fiscal period: 200804 thru: 200806

    my $self = shift;
    my $date = shift;
    return unless ( $date =~ m/^fiscal period: (\d{6}) thru: (\d{6})$/ );

    my $beginYear  = substr( $1, 0, 4 );
    my $beginMonth = substr( $1, 4, 2 );

    my $endYear  = substr( $2, 0, 4 );
    my $endMonth = substr( $2, 4, 2 );

    my $endMonthEnd = Days_in_Month( $endYear, $endMonth );

    my $format    = '%4d-%02d-%02d';
    my $beginDate = sprintf( $format, $beginYear, $beginMonth, 1 );
    my $endDate   = sprintf( $format, $endYear, $endMonth, $endMonthEnd );

    return ( $beginDate, $endDate );
}

sub _get_service_id {
    my $self        = shift;
    my $serviceName = lc shift;

    # minor adjustments to help the service name match ours
    $serviceName =~ s/ canada//;
    $serviceName =~ s/ us//;
    $serviceName =~ s/ uk//;
    $serviceName =~ s/Mix and Burn/mix_burn/i;

    return $self->getServiceID($serviceName);
}

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