package RPS::Import::YouTube;

use strict;

use Data::Dumper;

use lib '/app/tools/common/lib';
use Common::Date;
use Common::Util;
use Common::Consts;
use Common::Country;
use Math::BigFloat;
use Date::Calc qw(Days_in_Month Decode_Month);

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

# map version num to the field order
my %fieldMap = (
    1 => {
        date_start         => 7,
        date_end           => 8,
        album              => 15,
        track              => 16,
        possible_track     => 10,
        service_product_id => 14,
        units              => 19,
        price              => 21,
        currency           => 22,
    },
    2 => {
        date_start         => 7,
        date_end           => 8,
        track              => 13,
        artist             => 14,
        possible_track     => 10,
        service_product_id => 10,
        units              => 18,
        price              => 20,
        currency           => 21,
    },
    3 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 28,
        date_end_row       => 29,
        artist             => 11,
        track              => 12,
        service_product_id => 1,
        units              => 5,
        price              => 7,
        currency           => 8,
    },
    4 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 33,
        date_end_row       => 34,
        track              => 14,
        service_product_id => 1,
        units              => 5,
        price              => 11,
        currency           => 12,
    },
    5 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 33,
        date_end_row       => 34,
        track              => 12,
        service_product_id => 1,
        possible_track     => 1,
        units              => 3,
        price              => 9,
    },
    6 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 35,
        date_end_row       => 36,
        track              => 2,
        service_product_id => 1,
        possible_track     => 1,
        units              => 9,
        price              => 11,
    },
    8 => {
        date_start         => 7,
        date_end           => 8,
        service_product_id => 10,
        possible_track     => 10,
        isrc               => 15,
        upc                => 17,
        artist             => 18,
        track              => 19,
        album              => 20,
        label              => 21,
        units              => 22,
        price              => 24,
        currency           => 25,
    },
    9 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 28,
        date_end_row       => 29,
        service_product_id => 1,
        possible_track     => 1,
        units              => 5,
        price              => 7,
        currency           => 8,
        isrc               => 11,
        upc                => 13,
        artist             => 14,
        track              => 15,
        album              => 16,
        label              => 17,
    },
    10 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 34,
        date_end_row       => 35,
        service_product_id => 1,
        possible_track     => 1,
        units              => 4,
        price              => 10,
        multiple_claims    => 11,
        isrc               => 14,
        upc                => 16,
        artist             => 17,
        track              => 18,
        album              => 19,
        label              => 20,
    },
    11 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 38,
        date_end_row       => 39,
        service_product_id => 0,
        embeded_units      => 8,
        watched_units      => 9,
        price              => 13,
        media_type         => 6,
        isrc               => 17,
        upc                => 19,
        artist             => 20,
        track              => 21,
        album              => 22,
        label              => 23,
    },
    12 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 40,
        date_end_row       => 41,
        service_product_id => 0,
        embeded_units      => 9,
        watched_units      => 10,
        currency_code_col  => 1,
        currency_code_row  => 44,
        price              => 14,
        media_type         => 7,
        isrc               => 19,
        upc                => 21,
        artist             => 22,
        track              => 23,
        album              => 24,
        label              => 25,
    },
    13 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 39,
        date_end_row       => 40,
        service_product_id => 0,
        embeded_units      => 9,
        watched_units      => 10,
        currency_code_col  => 1,
        currency_code_row  => 42,
        price              => 14,
        media_type         => 7,
        isrc               => 18,
        upc                => 20,
        artist             => 21,
        track              => 22,
        album              => 23,
        label              => 24,
    },
    14 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 43,
        date_end_row       => 44,
        service_product_id => 0,
        embeded_units      => 9,
        watched_units      => 10,
        currency_code_col  => 1,
        currency_code_row  => 46,
        price              => 14,
        media_type         => 7,
        custom_id          => 20,
        isrc               => 21,
        upc                => 23,
        artist             => 24,
        track              => 25,
        album              => 26,
        label              => 27,
    },
    15 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 43,
        date_end_row       => 44,
        service_product_id => 0,
        embeded_units      => 9,
        watched_units      => 10,
        currency_code_col  => 1,
        currency_code_row  => 46,
        price              => 14,
        media_type         => 7,
        custom_id          => 19,
        isrc               => 20,
        upc                => 22,
        artist             => 23,
        track              => 24,
        album              => 25,
        label              => 26,
    },
    16 => {
        date_start_col    => 1,
        date_end_col      => 1,
        date_start_row    => 6,
        date_end_row      => 7,
        label             => 36,    #AK
        artist            => 33,    #AH
        upc               => 32,    #AG
        album             => 35,    #AJ
        isrc              => 30,    #AE
        track             => 34,    #AI
        units             => 11,    #L
        currency_code_col => 1,
        currency_code_row => 10,
        price             => 18,    #S
        media_type        => 9,     #J
    },
    17 => {
        date_start_col     => 1,
        date_end_col       => 1,
        date_start_row     => 36,
        date_end_row       => 37,
        service_product_id => 0,
        embeded_units      => 8,
        watched_units      => 9,
        price              => 12,
        media_type         => 6,
        isrc               => 16,
        upc                => 18,
        artist             => 19,
        track              => 20,
        album              => 21,
        label              => 22,
    },
    18 => {
        date_start_col    => 1,
        date_end_col      => 1,
        date_start_row    => 6,
        date_end_row      => 7,
        currency_code_col => 1,
        currency_code_row => 10,

        label         => 37,    # AL
        artist        => 34,    # AI
        upc           => 33,    # AH
        album         => 36,    # AK
        isrc          => 31,    # AF
        track         => 35,    # AJ
        embeded_units => 13,    # N
        watched_units => 12,    # M
        price         => 18,    # S
        media_type    => 9,     # J
    },
);

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

# This limits how many rows we want to look at when searching
# for the '# header table' section of a sales file.
#
use constant HEADER_LIMIT => 100;

#public methods

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

    my $lines       = $args{lines};
    my $fileObj     = $args{file};
    my $version     = $args{file}->VersionNum();
    my $fileName    = $fileObj->OrigFileName;
    my $track_start = "http://youtube.com/watch?v=";
    my ( $dateBegin, $dateEnd );
    my $offsets = $fieldMap{$version};

    return undef unless ( defined $lines && defined $version );

    if (   ( defined $offsets->{date_start_row} )
        && ( defined $offsets->{date_start_col} )
        && ( defined $offsets->{date_end_row} )
        && ( defined $offsets->{date_end_col} ) ) {

        my ( $f_dateBegin, $f_dateEnd );

        # Try to find the start/end dates in the header table of the sales
        # file using the field names.  This will allow some flexibility
        # should the date fields shift relative to the row offsets defined
        # in the fieldMap hash.  If this doesn't work, then we'll look for
        # the date using the row and column offsets.
        #
        my $headerFound;
        my $linenum = 1;
        foreach my $line (@$lines) {
            my $fieldName = $line->[0];
            $headerFound = 1 if ( $fieldName && $fieldName eq '# header table' );

            if ($headerFound) {
                $f_dateBegin = $line->[ $offsets->{date_start_col} ] if ( $fieldName eq 'report_period_start_date' );
                $f_dateEnd   = $line->[ $offsets->{date_end_col} ]   if ( $fieldName eq 'report_period_end_date' );
            }

            $linenum++;

            last if ( ( $f_dateBegin && $f_dateEnd ) || $linenum > HEADER_LIMIT );
        }

        # Use the default row/column offsets if we didn't find the dates
        # using the named fields above.
        #
        if ( !$f_dateBegin || !$f_dateEnd ) {
            ( $f_dateBegin, $f_dateEnd ) = (
                $lines->[ $offsets->{date_start_row} ]->[ $offsets->{date_start_col} ],
                $lines->[ $offsets->{date_end_row} ]->[ $offsets->{date_end_col} ]
            );
        }

        # Version 11 uses date in the format MM/DD/YY
        if ( $f_dateBegin =~ /(\d{1,2})\/(\d{1,2})\/(\d{4})/ ) {
            $f_dateBegin = sprintf( "%02d/%02d/%04d", $1, $2, $3 );
        } elsif ( $f_dateBegin =~ /(\d{1,2})\/(\d{1,2})\/(\d{2})/ ) {
            $f_dateBegin = sprintf( "%02d/%02d/20%02d", $1, $2, $3 );
        }

        if ( $f_dateEnd =~ /(\d{1,2})\/(\d{1,2})\/(\d{4})/ ) {
            $f_dateEnd = sprintf( "%02d/%02d/%04d", $1, $2, $3 );
        } elsif ( $f_dateEnd =~ /(\d{1,2})\/(\d{1,2})\/(\d{2})/ ) {
            $f_dateEnd = sprintf( "%02d/%02d/20%02d", $1, $2, $3 );
        }

        ( $dateBegin, $dateEnd ) = $self->_getDates( $f_dateBegin . " " . $f_dateEnd );

        if (   ( $f_dateBegin =~ /\d{2}\D\d{2}\D\d{4}/ )
            && ( $f_dateEnd =~ /\d{2}\D\d{2}\D\d{4}/ )
            && ( !$dateBegin || !$dateEnd ) ) {
            ( $dateBegin, $dateEnd ) = $self->SUPER::_getDates( date_begin => $f_dateBegin, date_end => $f_dateEnd, type => "us" );
        }

        if ( $f_dateBegin =~ /^\d+$/ ) {
            my $start = new Common::Date( date => $f_dateBegin, type => 'excel' );
            my $end   = new Common::Date( date => $f_dateEnd,   type => 'excel' );

            ( $dateBegin, $dateEnd ) = ( $start->monthBegin, $end->monthEnd );
        }
    }

    my $linenum = 1;
    foreach my $line (@$lines) {
        my $track              = $line->[ $offsets->{track} ];
        my $possible_track     = $line->[ $offsets->{possible_track} ];
        my $album              = $line->[ $offsets->{album} ] if ( defined $offsets->{album} );
        my $artist             = $line->[ $offsets->{artist} ] if ( defined $offsets->{artist} );
        my $service_product_id = $line->[ $offsets->{service_product_id} ]
          if ( defined $offsets->{service_product_id} );

        my $product_type = RPS::File::Sale::TYPE_TRACK;
        my $units;

        # This is the header row in ver 12 & 13.  Skip it.
        if ( $service_product_id && $service_product_id =~ /video_id/i ) {
            $linenum++;
            next;
        }

        if ( defined $offsets->{embeded_units} ) {
            $units = $line->[ $offsets->{embeded_units} ] + $line->[ $offsets->{watched_units} ];
        } else {
            $units = $line->[ $offsets->{units} ];
        }

        # JPK - Need to use the BigFloat package here, because these prices can be _extremely_ small.
        # In theory we support 8 decimal point precision (in the database), but perl will normally
        # resort to exponent notation once we get below 0.0009 or so.  This will cause problems...
        #
        my $f_price = $line->[ $offsets->{price} ];
        $f_price = undef if ( $f_price =~ /[a-z]/i );

        # In version 11 free tracks have '$-' in the price column;
        $f_price =~ s/\$-//g;
        $f_price =~ s/\$//g;

        my $country = "US";
        my $currency;
        $currency = $line->[ $offsets->{currency} ] if ( defined $offsets->{currency} );
        $currency = "USD" if ( !defined $offsets->{currency} );
        my $upc               = $line->[ $offsets->{upc} ]             if ( defined $offsets->{upc} );
        my $isrc              = $line->[ $offsets->{isrc} ]            if ( defined $offsets->{isrc} );
        my $client_product_id = $line->[ $offsets->{custom_id} ]       if ( defined $offsets->{custom_id} );
        my $label             = $line->[ $offsets->{label} ]           if ( defined $offsets->{label} );
        my $format_type       = RPS::File::Sale::FORMAT_STREAM;
        my $free              = 0;
        my $multiple_claims   = $line->[ $offsets->{multiple_claims} ] if ( defined $offsets->{multiple_claims} );
        $track = $track_start . $possible_track if ( $track eq "" && $album eq "" );

        if ( defined $offsets->{currency_code_row} ) {
            $currency = $line->[ $offsets->{currency_code_col} ] if ( $offsets->{currency_code_row} eq $linenum );
            die "Unable to determine currency code" unless ($currency);
        }

        if ( $upc && $upc =~ /^upc$/i && $isrc && $isrc =~ /^isrc$/i )    # header line, skip
        {
            $linenum++;
            next;
        }

        my $mediaType;
        my $f_mediaType = $line->[ $offsets->{media_type} ] if ( $offsets->{media_type} );

        if ( $f_mediaType && $f_mediaType =~ /^Visual/i ) {
            $mediaType = RPS::DB::Item::MediaType::kMediaTypeVideo;
        } else {
            $mediaType = RPS::DB::Item::MediaType::kMediaTypeAudio;
        }

        if ($label) {
            $label =~ s/(.*) \(.*\)/$1/;
        }

        if (   $units =~ /\d+/
            && ( defined $line->[ $offsets->{price} ] && ( $line->[ $offsets->{price} ] ne '' ) )
            && ( $track && $track ne "video_id" && $track !~ /commercial/ || $album )
            && $currency
            && $currency !~ /currency/i
            && ( ( $version != 10 ) || ( ( $version == 10 ) && ($multiple_claims) ) ) ) {
            my $price = Math::BigFloat->new($f_price) if ( defined $f_price );
            $price /= $units if ( $units > 1 );
            $free = 1 if ( $price == 0 );

            $product_type = RPS::File::Sale::TYPE_ALBUM if ( $track eq $track_start );

            ( $dateBegin, $dateEnd ) = _getDates( $line->[ $offsets->{date_start} ] . " " . $line->[ $offsets->{date_end} ] )
              if ( ( defined $offsets->{date_start} )
                && ( defined $offsets->{date_end} ) );

            unless ( $dateBegin && $dateEnd ) {
                print STDERR "Couldn't get dates from " . $line->[ $offsets->{date_start} ] . " " . $line->[ $offsets->{date_end} ] . "\n";
                $self->errstr( "couldn't get dates from " . $line->[ $offsets->{date_start} ] . " " . $line->[ $offsets->{date_end} ] );
                return undef;
            }

            my $sale = RPS::Import::SaleRec->new();
            $sale->productType($product_type);
            $sale->formatType($format_type);
            $sale->dateBegin($dateBegin);
            $sale->dateEnd($dateEnd);
            $sale->trackName($track)                   if ( $track ne "" );
            $sale->albumName($album)                   if ( defined $offsets->{album} && $album ne "" );
            $sale->artistName($artist)                 if ( defined $offsets->{artist} && $artist ne "" );
            $sale->upc($upc)                           if ( defined $offsets->{upc} && $upc ne "" );
            $sale->isrc($isrc)                         if ( defined $offsets->{isrc} && $isrc ne "" );
            $sale->clientProductID($client_product_id) if ( defined $offsets->{custom_id} && $client_product_id ne "" );
            $sale->labelName($label)                   if ( defined $offsets->{label} && $label ne "" );
            $sale->units($units);
            $sale->price($price);
            $sale->free($free);
            $sale->mediaType($mediaType);
            $sale->countryCode($country);
            $sale->currencyCode($currency);
            $sale->lineNum($linenum);
            $self->_insertSale( sale => $sale );
        }

        #else { print STDERR "Skip-> l:".$linenum." u:".$units." p:".$price." t: ".$track." c:".$currency."<-Skip\n";}
        $linenum++;
    }
    return $linenum;
}

#
# Private methods
#

sub _getDates {
    my $self = shift;
    my $date = shift;
    my ( $beginDate, $endDate );

    #print STDERR "|>".$date."<|\n";
    if ( $date =~ m/(\d+)\D(\d+)\D(\d{4}) (\d+)\D(\d+)\D(\d{4})/ ) {
        $beginDate = $3 . "-" . $1 . "." . $2;
        $endDate   = $6 . "-" . $4 . "-" . $5;
    } elsif ( $date =~ m/(\d{4})\D(\d+)\D(\d+) (\d{4})\D(\d+)\D(\d+)/ ) {
        $beginDate = $1 . "-" . $2 . "-" . $3;
        $endDate   = $4 . "-" . $5 . "-" . $6;
        return ( $beginDate, $endDate );
    }
    return undef;
}

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