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.
###
