package RPS::Import::ADA::v13;

use strict;

use Date::Calc qw(Days_in_Month Decode_Month);
use Data::Dumper;

use lib '/app/tools/common/lib';
use Common::Util qw(normalize_date normalize_upc);
use Common::Country;

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

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

use base 'RPS::Import::MapFaceBase';
use base 'RPS::Import::ADA::ADACommon';

sub _headerIdentifier { ( upc => 'UPC' ) }

sub _validateFieldMap {}

sub _fieldMap {
    
    my $self = shift;
    
    my $sheetName = lc $self->{sheetname};    
    
    # Need to be able to accept flat files too.
    if (!$sheetName) {
        $sheetName = 'digital sales';   
    }
    
    my %fieldMaps = (
        'statement summary' => {
        },

        'digital sales' => {
            label            => 0,  # A 
            serviceID        => 11, # L
            countryCode      => 13, # N
            productType      => 5,  # F
            formatType       => 15, # P
            serviceProductID => 9,  # J
            clientProductID  => 8,  # I
            artistName       => 3,  # D
            upc              => 6,  # G

            albumName        => 4,  # E  can be track name (depending on product type)
            trackName        => 4,  # E

            isrc             => 7,  # H
            units            => 18, # S
            price            => 23, # X
        },        
    );
    if ($fieldMaps{$sheetName}) {
        return $fieldMaps{$sheetName};
    } else {
        print STDERR "ADA v13: Illegal sheet '$sheetName'\n";            
        die "Sheet '$sheetName' is not valid"; 
    }    
}

sub _unverifiedFieldMap {
    
    my $self = shift;
    
    my $sheetName = lc $self->{sheetname};    
    
    # Need to be able to accept flat files too.
    if (!$sheetName) {
        $sheetName = 'digital sales';   
    }
    
    my %fieldMaps = (
        'statement summary' => {
            date_row => 3,  # Row 4
            date_col => 1,  # Col B
        },

        'digital sales' => {
        },        
    );
    if ($fieldMaps{$sheetName}) {
        return $fieldMaps{$sheetName};
    } else {
        print STDERR "ADA v13: Illegal sheet '$sheetName'\n";            
        die "Sheet '$sheetName' is not valid"; 
    }    
}


my %mediaProductTypeMap = (
   'album' => {
      product_type => RPS::File::Sale::TYPE_ALBUM,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'audio clip' => {
      product_type => RPS::File::Sale::TYPE_TRACK,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'ep' => {
      product_type => RPS::File::Sale::TYPE_ALBUM,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'full length' => {
      product_type => RPS::File::Sale::TYPE_ALBUM,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'full length release' => {
      product_type => RPS::File::Sale::TYPE_ALBUM,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'full length recording (track)' => {
      product_type => RPS::File::Sale::TYPE_TRACK,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'mastertone' => {
      product_type => RPS::File::Sale::TYPE_TRACK,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'music video ringer' => {
      product_type => RPS::File::Sale::TYPE_TRACK,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeVideo,
   },
   'ringbacktone' => {
      product_type => RPS::File::Sale::TYPE_TRACK,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'ringtone' => {
      product_type => RPS::File::Sale::TYPE_TRACK,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'single' => {
      product_type => RPS::File::Sale::TYPE_ALBUM,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'single track' => {
      product_type => RPS::File::Sale::TYPE_TRACK,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'track' => {
      product_type => RPS::File::Sale::TYPE_TRACK,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },
   'track (step)' => {
      product_type => RPS::File::Sale::TYPE_TRACK,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
   },   
   'video' => {
      product_type => RPS::File::Sale::TYPE_TRACK,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeVideo,
   },
   'videosingle' => {
      product_type => RPS::File::Sale::TYPE_ALBUM,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeVideo,
   },
   'video single' => {
      product_type => RPS::File::Sale::TYPE_ALBUM,
      media_type   => RPS::DB::Item::MediaType::kMediaTypeVideo,
   },
);

sub currencyCode { 'GBP' }

sub _getDateBegin { shift->{_dateBegin} }
sub _getDateEnd   { shift->{_dateEnd} }

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

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

    # For some sales files (huge XLSX files), we'll have to manually save the
    # XLSX detail data as a flat-file, and extract the date information from
    # from the filename itself.  This is a workaround until we come up with
    # a solution for handling "too large" XLSX files.  See FB311.
    #
    my $dateBegin;
    my $dateEnd;
    
    my $isFlatFile = ( scalar @{$args{sheets}} == 1 ) ? 1 : undef;
    my $fileName = $args{file}->OrigFileName();
    my $sheet_count = 0;
    my $sheet_names = $args{sheet_names};    
    
    if( $isFlatFile )
    {
        if( $fileName =~ /(\d{4})(\d{2})(\d{2})_(\d{4})(\d{2})(\d{2})/ )   # YYYYMMDD_YYYYMMDD.
        {
            $dateBegin = sprintf("%04d-%02d-%02d", $1, $2, $3);
            $dateEnd   = sprintf("%04d-%02d-%02d", $4, $5, $6);
        }
    }
    else
    {
        #-----------------------------------------
        # Extract date information from header tab
        #-----------------------------------------
        my $dateField;
        foreach my $sheet(@{ $args{sheets} })
        {
            my $sheetName = $sheet_names->[$sheet_count];

            my $sheetIndex = lc $sheetName;

            if ($sheetIndex eq 'statement summary')
            {
                # Get the date information from the summary sheet
                $self->{sheetname} = $sheetName;
                my $data = $self->_fieldMap();

                my $dateRow = $data->{date_row};
                my $dateCol = $data->{date_col};

                $dateField = $sheet->[$dateRow][$dateCol];

                if ( $dateField =~ m/Period: (\d{1,2})\/(\d{1,2})\/(\d{4}) . (\d{1,2})\/(\d{1,2})\/(\d{4})/ )
                {
                    $dateBegin = join("-", $3, sprintf("%02d",$1), sprintf("%02d",$2) );
                    $dateEnd   = join("-", $6, sprintf("%02d",$4), sprintf("%02d",$5) );

                    ($dateBegin, $dateEnd) = $self->_getDates( date_begin => $dateBegin, date_end => $dateEnd );
                }

                if( !$dateBegin && !$dateEnd )
                {
                    # If we don't find the date where we expect it, then the actual
                    # cell location has likely shifted due to one or more blank columns
                    # to the left and/or blank rows at the top.  The following will
                    # attempt to find the date cell within the first 5 columns/rows.
                    #
                    foreach my $col (0..4)
                    {
                        foreach my $row (0..4)
                        {
                            my $cellData = $sheet->[$row][$col];

                            if ( $cellData =~ m/Period: (\d{1,2})\/(\d{1,2})\/(\d{4}) . (\d{1,2})\/(\d{1,2})\/(\d{4})/ )
                            {

                                $dateBegin = join("-", $3, sprintf("%02d",$1), sprintf("%02d",$2) );
                                $dateEnd   = join("-", $6, sprintf("%02d",$4), sprintf("%02d",$5) );

                                ($dateBegin, $dateEnd) = $self->_getDates( date_begin => $dateBegin, date_end => $dateEnd );

                            }
                            last if ( $dateBegin || $dateEnd );
                        }

                        last if ( $dateBegin || $dateEnd );
                    }

                }
            }# statement summary

            last if ( $dateField );
            $sheet_count++;
        }
    }
    
    $self->{_dateBegin} = $dateBegin;
    $self->{_dateEnd}   = $dateEnd;
}

sub countryCode {
    my $self = shift;

    if (defined $self->_getByFieldName( 'countryCode' )) {
        my $name = $self->_getByFieldName( 'countryCode' );
	    my $country = Common::Country->Get( $name );
		if ($country) {
			return $country->alpha2();
		} else {
			return $name;
		}        
    } 
}

sub units {
    my $self = shift;
    my $units = $self->_getByFieldName( 'units' ) || return;
    $units =~ s/,//g;
    $units =~ s/\s+//g;   
    if( $units =~ /^\((\d*\.?\d*)\)$/ )
    {
        $units = $1 * -1;
    }
     
    my $price = $self->_getByFieldName( 'price' );
    if( $price =~ /^\((\d*\.?\d*)\)$/ )
    {
        $price = $1 * -1;
    }      

    if ( $units && $units < 0 && $price && $price > 0 )
    {               
        return $self->handleError( "Negative units with revenue", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
    }

    # For this importer, We'll follow the sign of the revenue to determine
    # the sign of the units (FB1168).
    #
    if( $price && $units )
    {
        if( $price < 0 )
        {
            $units = 0 - $units if( $units > 0 ); # price is negative, force negative units
        }
        else
        {
            $units = abs($units) if( $units < 0 ); # price is positive, force positive units
        }
    }

    return $units;
}

sub price {
    my $self = shift;
     
    my $price = $self->_getByFieldName( 'price' );
    if( $price =~ /^\((\d*\.?\d*)\)$/ )
    {
        $price = $1;
    }     
    
    return $price;     
}

sub free 
{
    my $self = shift;
    my $price = $self->_getByFieldName( 'price' );
    return ( $price == 0 ) ? 1 : 0;
}

            
sub _isValidSaleRecord 
{
    my $self = shift;
    my $units  = $self->units;
    my $price  = $self->price;
    my $releaseType = lc $self->_getByFieldName( 'productType' );

    return undef if ( !$units && $price && $price < 0 );
    return undef if ( $releaseType =~ /wallpaper/i );
    return $self->SUPER::_isValidSaleRecord();
}
          

sub formatType 
{
    my $self = shift;
    my $releaseType = lc $self->_getByFieldName( 'productType' );
    my $deliveryFormat = lc $self->_getByFieldName( 'formatType' );

    my $formatType = $self->_getFormatType( release_type => $releaseType, delivery_format => $deliveryFormat );
    if ($formatType) 
    {
        return $formatType;
    }
    else
    { 
        return $deliveryFormat;
    }   
}  

sub mediaType           
{
    my $self = shift;
    my $releaseType = lc $self->_getByFieldName( 'productType' );
    my $deliveryFormat = lc $self->_getByFieldName( 'formatType' );

    my $mediaType;
    
    if ($releaseType eq '' && $deliveryFormat =~ /^usergenmastertone$/i) 
    {
        $mediaType   = RPS::DB::Item::MediaType::kMediaTypeAudio;
    }
    else
    {
        $mediaType = $mediaProductTypeMap{ $releaseType }->{ media_type };
    }
    
    if ($mediaType)
    {               
        return $mediaType
    } else {
        return $releaseType;
    }
}

sub productType           
{
    my $self = shift;
    my $releaseType = lc $self->_getByFieldName( 'productType' );
    my $deliveryFormat = lc $self->_getByFieldName( 'formatType' );

    my $productType;
    
    if ( $releaseType eq '' && $deliveryFormat =~ /^usergenmastertone$/i ) 
    {
        $productType = RPS::File::Sale::TYPE_TRACK;
    }
    # Per FB16627: If the release type is video, then
    #   product type is track if ISRC is populated, otherwise
    #   product type is album if UPC is populated.
    #
    elsif ( $releaseType =~ /^video$/i || $releaseType =~ /^video.*single$/i )    
    {
        my $_isrc = $self->_getByFieldName( 'isrc' ) if (defined $self->_getByFieldName( 'isrc' ));  
        my $_upc  = $self->_getByFieldName( 'upc' )  if (defined $self->_getByFieldName( 'upc' ) );  
        if( $_isrc )
        {
            $productType = RPS::File::Sale::TYPE_TRACK;
        }
        elsif( $_upc )
        {
            $productType = RPS::File::Sale::TYPE_ALBUM;
        }        
    }
    else
    {
        $productType = $mediaProductTypeMap{ $releaseType }->{ product_type };
    }
    
    if ($productType)
    {               
        return $productType
    } else {
        return $releaseType;
    }
}

sub serviceID {
    my $self = shift;
    my $serviceName = $self->_getByFieldName( 'serviceID' ) || return;

    my $serviceID = $self->getServiceID(lc ($serviceName)); # See ADACommon
    if (!$serviceID)
    {                  
        return $self->handleError("Unknown service: $serviceName", RPS::DB::Item::SaleImportError::kErrorService);
    } 
    else
    {
        return $serviceID;   
    }
}

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

    if ( $isrc )
    {
        return Common::Util::normalize_isrc($isrc);
    }  
}

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

    if ( $upc )
    {
        return Common::Util::normalize_upc($upc);
    }  
}

sub albumName {
    my $self = shift;
    my $isrc = $self->_getByFieldName( 'isrc' );
    my $name = $self->_getByFieldName( 'albumName' );
    if ( !$isrc )
    {    
        return $name;
    } 
}

sub trackName {
    my $self = shift;
    my $isrc = $self->_getByFieldName( 'isrc' );
    my $name = $self->_getByFieldName( 'trackName' );
    if ( $isrc )
    {    
        return $name;
    }
}
                             

sub _getFormatType
{
    my $self = shift;
    my %args = @_;
    my $releaseType     = $args{release_type};
    my $deliveryFormat  = $args{delivery_format};

    my $formatType;

    if( $releaseType eq 'mastertone' )
    {
        if( $deliveryFormat eq 'download' )
        {
            $formatType = RPS::File::Sale::FORMAT_DOWNLOAD;
        }
        elsif( $deliveryFormat eq 'stream' )
        {
            $formatType = RPS::File::Sale::FORMAT_STREAM;
        }
    }
    elsif( $releaseType eq 'music video ringer' )
    {
        $formatType = RPS::File::Sale::FORMAT_DOWNLOAD if( $deliveryFormat eq 'download' );
    }
    elsif( $releaseType eq 'ringbacktone' )
    {
        if( $deliveryFormat eq 'download' )
        {
            $formatType = RPS::File::Sale::FORMAT_RINGTONE;
        }
        elsif( $deliveryFormat eq 'stream' )
        {
            $formatType = RPS::File::Sale::FORMAT_STREAM;
        }
    }
    elsif( $releaseType eq 'album'        ||
           $releaseType eq 'ep'           ||
           $releaseType eq 'single track' ||
           $releaseType eq 'single'       ||
           $releaseType eq 'track (step)' ||
           $releaseType eq 'track'        ||
           $releaseType eq 'audio clip'   ||
           $releaseType eq 'full length'  ||
           $releaseType eq 'full length recording (track)' )
    {
        if( $deliveryFormat eq 'download' )
        {
            $formatType = RPS::File::Sale::FORMAT_DOWNLOAD;
        }
        elsif( $deliveryFormat eq 'stream' )
        {
            $formatType = RPS::File::Sale::FORMAT_STREAM;
        }
    }
    elsif( $releaseType eq 'full length' )
    {
        if( $deliveryFormat eq 'download' )
        {
            $formatType = RPS::File::Sale::FORMAT_DOWNLOAD;
        }
    }
    elsif( $releaseType eq 'full length release' )
    {
        if( $deliveryFormat eq 'download' )
        {
            $formatType = RPS::File::Sale::FORMAT_DOWNLOAD;
        }
        elsif( $deliveryFormat eq 'stream' )
        {
            $formatType = RPS::File::Sale::FORMAT_STREAM;
        }
    }

    # The following delivery formats apply to all release types
    #
    if( $deliveryFormat eq 'emastertone' ||
        $deliveryFormat eq 'eringback' )
    {
        $formatType = RPS::File::Sale::FORMAT_RINGTONE;
    }

    elsif( $deliveryFormat eq 'emdalbum' ||
           $deliveryFormat eq 'emdtrack' ||
           $deliveryFormat eq 'evd' )
    {
        $formatType = RPS::File::Sale::FORMAT_DOWNLOAD;
    }

    elsif( $deliveryFormat eq 'emdalbumstreaming' ||
           $deliveryFormat eq 'emdtrackstreaming' ||
           $deliveryFormat eq 'evdstreaming' ||
           $deliveryFormat eq 'usergenmastertone' )
    {
        $formatType = RPS::File::Sale::FORMAT_STREAM;
    }
    elsif( $releaseType eq 'videosingle' ||
           $releaseType eq 'video single' )
    {
        if( $deliveryFormat eq 'stream' ) {
            $formatType = RPS::File::Sale::FORMAT_STREAM;
        }
        elsif( $deliveryFormat eq 'download' ) {
            $formatType = RPS::File::Sale::FORMAT_DOWNLOAD;
        }
    }

    return $formatType;
}

# _getDates: helper method to process US or UK formatted dates.
#
# The end date is checked to see if it's a US or UK-formatted date, with
# the assumption that the day will be be greater than 12 (most likely
# between 28-31).
# Note: the end date is used in determining the sales period.
#
sub _getDates {
    my $self  = shift;
    my %args  = @_;

    my $_dateBegin = $args{date_begin};  # YYYY-MM-DD or YYYY-DD-MM
    my $_dateEnd   = $args{date_end};    # YYYY-MM-DD or YYYY-DD-MM

    my $dateEnd = $_dateEnd;

    my( $beginYear, $beginMonth, $beginDay ) = split("-", $_dateBegin);
    my( $endYear,   $endMonth,   $endDay   ) = split("-", $_dateEnd);

    if( $endMonth > 12 )
    {
        $dateEnd = join("-", $endYear, $endDay, $endMonth); # swap the month/day fields
    }

    return $self->SUPER::_getDates( date_begin => $dateEnd );
}

## MapFace Stuff
sub _mapFaceCompatibleVersions {
	return (13,20);
}

sub _mapFaceServiceID {
	return ('serviceID', 'countryCode');
}

sub _mapFaceCountryCode {
	return ('countryCode');
}

sub _mapFaceProductType {
	return ('formatType', 'productType');
}

sub _mapFaceFormatType {
	return ('formatType', 'productType');
}

sub _mapFaceMediaType {
	return ('formatType', 'productType');
}

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