package RPS::Import::ADA::v35;

use strict;
use warnings;

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

use parent qw/RPS::Import::MapFaceBase RPS::Import::ImporterMixed/;

sub physical { 0 }

my %sheetToHeaderMap = (
    'hitco'                 => [],    # skip this tab
    'downloads'             => [ 'digital', 'option1' ],
    'streams'               => [ 'digital', 'option2' ],
    'streams_alt1'          => [ 'digital', 'option3' ],    # alternate tab with the same name 'streams'
    'international digital' => [ 'digital', 'option4' ],
);

sub _fieldMapExtended {
    {
        digital => {
            # downloads
            option1 => {
                labelName   => 'B',
                serviceID   => 'T',
                dateBegin   => 'H',
                dateEnd     => 'H',
                productType => 'K',
                formatType  => 'D',
                artistName  => 'L',
                upc         => 'I',
                albumName   => 'M',
                isrc        => 'J',
                trackName   => 'M',
                units       => 'P',
                price       => 'R',
                mediaType   => 'D',
            },
            # streams
            option2 => {
                labelName   => 'B',
                serviceID   => 'S',
                dateBegin   => 'H',
                dateEnd     => 'H',
                productType => 'K',
                formatType  => 'D',
                artistName  => 'L',
                upc         => 'I',
                isrc        => 'J',
                trackName   => 'M',
                units       => 'O',
                price       => 'Q',
                mediaType   => 'D',
            },
            # streams (alternate tab with the same name 'streams' but shifted cols)
            option3 => {
                labelName   => 'B',
                serviceID   => 'R',
                dateBegin   => 'A3',
                dateEnd     => 'A3',
                productType => 'J',
                formatType  => 'D',
                artistName  => 'K',
                upc         => 'H',
                isrc        => 'I',
                trackName   => 'L',
                units       => 'N',
                price       => 'P',
                mediaType   => 'D',
            },
            # international digital
            option4 => {
                labelName   => 'B',
                serviceID   => 'U',
                countryCode => 'H',
                dateBegin   => 'G',
                dateEnd     => 'G',
                productType => 'M',
                formatType  => 'D',
                artistName  => 'I',
                upc         => 'K',
                albumName   => 'J',
                isrc        => 'L',
                trackName   => 'J',
                units       => 'P',
                price       => 'R',
                mediaType   => 'D',
            },
        }
    };
}

sub _unverifiedFieldMapExtended { {} }

sub _headerIdentifierExtended {
    my $self = shift;

    my $hHeader = {
        digital => {
            # downloads
            option1 => {
                formatType => 'Media Code',
            },
            # streams
            option2 => {
                formatType => 'Media Code',
            },
            # streams (alternate tab with the same name 'streams' but shifted cols)
            option3 => {
                formatType => 'Media Code',
            },
            # international digital
            option4 => {
                formatType => 'Media Code',
            },
        }
    };

    return $self->_chooseHeaderBlock($hHeader);
}

my %sheetRules = (
    'downloads' => {
        countryCode  => 'US',
        currencyCode => 'USD',
        productType  => sub {
            return RPS::File::Sale::TYPE_TRACK if $_[1] =~ /^ISRC$/i;
            return RPS::File::Sale::TYPE_ALBUM if $_[1] =~ /^UPC$/i;
            return;
        },
        formatType => sub {
            return RPS::File::Sale::FORMAT_DOWNLOAD if $_[1] =~ /^(?:EMD(?:Album|Track)|EVD)$/i;
            return;
        },
        albumName => sub {
            return $_[1] if $_[0]->productType eq RPS::File::Sale::TYPE_ALBUM;
            return;
        },
        isrc => sub {
            return $_[1] if $_[0]->productType eq RPS::File::Sale::TYPE_TRACK;
            return;
        },
        trackName => sub {
            return $_[1] if $_[0]->productType eq RPS::File::Sale::TYPE_TRACK;
            return;
        },
        mediaType => sub {
            return RPS::DB::Item::MediaType::kMediaTypeAudio if $_[1] =~ /^EMD(?:Album|Track)$/i;
            return RPS::DB::Item::MediaType::kMediaTypeVideo if $_[1] =~ /^EVD$/i;
            return;
        },
    },
    'streams' => {
        countryCode  => 'US',
        currencyCode => 'USD',
        productType  => sub {
            return RPS::File::Sale::TYPE_TRACK if $_[1] =~ /^ISRC$/i;
            return;
        },
        formatType => sub {
            return RPS::File::Sale::FORMAT_STREAM if $_[1] =~ /^(?:EMDTrack|EVD)Streaming$/i;
            return;
        },
        mediaType => sub {
            return RPS::DB::Item::MediaType::kMediaTypeAudio if $_[1] =~ /^EMDTrackStreaming$/i;
            return RPS::DB::Item::MediaType::kMediaTypeVideo if $_[1] =~ /^EVDStreaming$/i;
            return;
        },
    },
    'streams_alt1' => {
        countryCode  => 'US',
        currencyCode => 'USD',
        productType  => sub {
            return RPS::File::Sale::TYPE_TRACK if $_[1] =~ /^ISRC$/i;
            return;
        },
        formatType => sub {
            return RPS::File::Sale::FORMAT_STREAM if $_[1] =~ /^(?:EMDTrack|EVD)Streaming$/i;
            return;
        },
        mediaType => sub {
            return RPS::DB::Item::MediaType::kMediaTypeAudio if $_[1] =~ /^EMDTrackStreaming$/i;
            return RPS::DB::Item::MediaType::kMediaTypeVideo if $_[1] =~ /^EVDStreaming$/i;
            return;
        },
    },
    'international digital' => {
        currencyCode => 'USD',
        productType  => sub {
            return RPS::File::Sale::TYPE_TRACK if $_[1] =~ /^ISRC$/i;
            return RPS::File::Sale::TYPE_ALBUM if $_[1] =~ /^UPC$/i;
            return;
        },
        formatType => sub {
            return RPS::File::Sale::FORMAT_DOWNLOAD if $_[1] =~ /^(?:EMD(?:Album|Track)|EVD)$/i;
            return RPS::File::Sale::FORMAT_STREAM if $_[1] =~ /^(?:EMDTrack|EVD)Streaming$/i;
            return;
        },
        albumName => sub {
            return $_[1] if $_[0]->productType eq RPS::File::Sale::TYPE_ALBUM;
            return;
        },
        isrc => sub {
            return $_[1] if $_[0]->productType eq RPS::File::Sale::TYPE_TRACK;
            return;
        },
        trackName => sub {
            return $_[1] if $_[0]->productType eq RPS::File::Sale::TYPE_TRACK;
            return;
        },
        mediaType => sub {
            return RPS::DB::Item::MediaType::kMediaTypeAudio if $_[1] =~ /^(?:EMD(?:Album|Track)|EMDTrackStreaming)$/i;
            return RPS::DB::Item::MediaType::kMediaTypeVideo if $_[1] =~ /^EVD(?:Streaming)?$/i;
            return;
        },
    },
);

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,
);

sub labelName {
    my $self = shift;

    my $name = $self->_getByFieldName('labelName') || '';
    my $result = $self->_ruleException();

    return defined $result ? $result : $name;
}

sub serviceID {
    my $self = shift;

    my $result = $self->_ruleException();
    return $result if $result;

    my $service = lc( $self->_getByFieldName('serviceID') || '' );
    my $serviceID = $self->getServiceID( lc($service) ) || $RPS::Import::ServiceMap::SERVICE_ALIASES{ lc $service };

    return defined $serviceID
        ? $serviceID
        : $self->handleError( "Unknown service: '$service'", RPS::DB::Item::SaleImportError::kErrorService );
}

sub countryCode {
    my $self = shift;

    my $result = $self->_ruleException();
    return $result if $result;

    my $name = $self->_getByFieldName('countryCode') || '';
    $name =~ s/^\s*|\s*$//g;

    my $oCountry = Common::Country->Get($name) if $name;

    return $oCountry
        ? $oCountry->alpha2()
        : $self->handleError( "Unknown country: '$name'.", RPS::DB::Item::SaleImportError::kErrorCountry );
}

sub saleDates {
    my $self = shift;

    # MM/DD/YYYY
    my $dateBegin = $self->_getByFieldName('dateBegin') || '';
    if ( $dateBegin =~ /^(\d{2}).(\d{2}).(\d{4})$/i ) {
        return $self->_getDates( date_begin => sprintf("%04d-%02d-%02d", $3, $1, $2) );
    }
    # YYYY-MM-DD
    elsif ( $dateBegin =~ /^(\d{4}).(\d{2}).(\d{2})$/i ) {
        return $self->_getDates( date_begin => sprintf("%04d-%02d-%02d", $1, $2, $3) );
    }
    elsif ( $dateBegin =~ /^(\d{5})$/) {
        return $self->_getDates( date_begin => Spreadsheet::ParseExcel::Utility::ExcelFmt( "yyyy-mm-dd", $1 ) );
    }
    # May 2022
    elsif ( $dateBegin =~ /^([a-z]+) (\d{4})$/i ) {
        my $month = lc( substr($1, 0, 3) );
        my $year  = $2;
        return $self->_getDates( date_begin => sprintf("%04d-%02d-%02d", $year, $months{$month}, 1) );
    }
    # 01-MAR-22
    elsif ( $dateBegin =~ /^(\d{1,2})-([a-z]+)-(\d{2})$/i ) {
        my $day   = $1;
        my $month = lc( substr($2, 0, 3) );
        my $year  = "20$3";
        return $self->_getDates( date_begin => sprintf("%04d-%02d-%02d", $year, $months{$month}, $day) );
    }

    return $self->fail("Unable to determine date from: '$dateBegin'." );
}

sub productType {
    my $self = shift;

    my $type = $self->_getByFieldName('productType') || '';
    my $result = $self->_ruleException( lc $type );

    return defined $result
        ? $result
        : $self->handleError( "Unknown product_type: '$type'.", RPS::DB::Item::SaleImportError::kErrorProductType );
}

sub formatType {
    my $self = shift;

    my $type = $self->_getByFieldName('formatType') || '';
    my $result = $self->_ruleException( lc $type );

    return defined $result
        ? $result
        : $self->handleError( "Unknown format_type: '$type'.", RPS::DB::Item::SaleImportError::kErrorFormatType );
}

sub artistName {
    my $self = shift;

    my $name = $self->_getByFieldName('artistName') || '';
    my $result = $self->_ruleException($name);

    return defined $result ? $result : $name;
}

sub upc {
    my $self = shift;

    my $upc = $self->_getByFieldName('upc') || '';
    my $result = $self->_ruleException($upc);

    return defined $result ? $result : $upc;
}

sub albumName {
    my $self = shift;

    my $name = $self->_getByFieldName('albumName') || '';
    my $result = $self->_ruleException($name);

    return defined $result ? $result : $name;
}

sub isrc {
    my $self = shift;

    my $isrc = $self->_getByFieldName('isrc') || '';
    my $result = $self->_ruleException($isrc);

    return defined $result ? $result : $isrc;
}

sub trackName {
    my $self = shift;

    my $name = $self->_getByFieldName('trackName') || '';
    my $result = $self->_ruleException($name);

    return defined $result ? $result : $name;
}

sub mediaType {
    my $self = shift;

    my $type = $self->_getByFieldName('mediaType') || '';
    my $result = $self->_ruleException( lc $type );

    return defined $result
        ? $result
        : $self->handleError( "Unknown media_type: '$type'.", RPS::DB::Item::SaleImportError::kErrorMediaType );
}

# digital
sub price {
    my $self = shift;

    my $price = abs( $self->_getByFieldName('price') || 0 );
    my $result = $self->_ruleException($price);

    return defined $result ? $result : $price;
}
sub unitPrice { abs shift->SUPER::unitPrice }
sub units {
    my $self = shift;

    my $units = $self->_getByFieldName('units') || 0;
    my $price = $self->_getByFieldName('price') || 0;

    if ( $price > 0 ) {
        $units = $units ? abs($units) : 1;
    } elsif ( $price < 0 ) {
       $units = $units ? -1 * abs($units) : -1;
    }

    return $units;
}

# mapFace
sub _mapFaceServiceID   { 'serviceID' }
sub _mapFaceCountryCode { 'countryCode' }
sub _mapFaceProductType { 'productType' }
sub _mapFaceFormatType  { 'formatType' }
sub _mapFaceMediaType   { 'mediaType' }


sub _chooseHeaderBlock {
    my ($self, $hHeader) = @_;

    my $hResult = {};

    my $sheetName = $self->_sheetName || return $hHeader;
    if ( exists $sheetToHeaderMap{$sheetName} && @{ $sheetToHeaderMap{$sheetName} } ) {
        my $type   = $sheetToHeaderMap{$sheetName}[0];
        my $option = $sheetToHeaderMap{$sheetName}[1];
        $hResult = {
            $type => {
                $option => $hHeader->{$type}{$option}
            }
        };
    }

    return $hResult;
}

sub _ruleException {
    my ( $self, @args ) = @_;

    my $sheet = $self->_sheetName;
    my ($method) = ( caller(1) )[3] =~ /.*::(.+)$/;
    return unless exists $sheetRules{$sheet} && exists $sheetRules{$sheet}{$method};

    my $rule = $sheetRules{$sheet}{$method};
    return ref $rule eq 'CODE' ? &$rule( $self, @args ) : $rule;
}

sub _sheetName {
    my $self = shift;

    my $name = $self->sheetname() || '';

    if ( $self->sheetname =~ /^streams$/i && $self->{_streams_alt} ) {
        $name .= $self->{_streams_alt} || '';
    }

    $name =~ s/^\s+|\s+$//g;
    $name =~ s/[^0-9a-zA-Z\s_-]//g;
    $name =~ s/\s+/ /g;

    return lc $name;
}

sub _processSheet {
    my ( $self, $sheet, $sheetnum ) = @_;

    # check if the Streams tab has an alternate header, if so change its name to Streams_alt1
    if ( $self->sheetname =~ /^streams$/i ) {
        my $limit = 50;
        foreach my $aRow ( @$sheet ) {
            my $firstCol = $$aRow[0] || '';
            my $flagCol  = $$aRow[7] || '';
            if ( $firstCol =~ /^Company$/i && $flagCol !~ /^Transaction Date$/i ) {
                $self->{_streams_alt} = '_alt1';
                last;
            }
            last unless --$limit;
        }
    }

    if ( exists $sheetToHeaderMap{ $self->_sheetName } ) {
        my $headerFound = $self->SUPER::_processSheet( $sheet, $sheetnum );
        return $headerFound;
    }

    $self->fail( "Encountered unrecognized sheet " . $self->_sheetName );
}

sub _isValidSaleRecord {
    my $self = shift;

    return defined $self->units && defined $self->price && $self->labelName;
}


1;