package RPS::Import::DashGo::v3;

use strict;
use warnings;
use POSIX qw/strftime/;

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

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

use base qw(RPS::Import::MapFaceBase RPS::Import::Importer);

sub _fieldMap {
    my $self = shift;

    my %map = (
        3 => {
            labelName    => 'E',
            dateBegin    => 'A',
            serviceID    => 'B',
            countryCode  => 'C',
            productType  => 'P',
            formatType   => 'P',
            artistName   => 'D',
            upc          => 'H',
            albumName    => 'F',
            isrc         => 'K',
            trackName    => 'I',
            units        => 'N',
            price        => 'Z',
            mediaType    => 'P',
            currencyCode => 'T'
        },
        4 => {
            labelName    => 'E',
            dateBegin    => 'A',
            serviceID    => 'B',
            countryCode  => 'C',
            productType  => 'P',
            formatType   => 'P',
            artistName   => 'D',
            upc          => 'H',
            albumName    => 'F',
            isrc         => 'K',
            trackName    => 'I',
            units        => 'N',
            price        => 'AA',
            mediaType    => 'P',
            currencyCode => 'T'
        },
        5 => {
            labelName    => 'E',
            dateBegin    => 'A',
            serviceID    => 'B',
            countryCode  => 'C',
            productType  => 'Q',
            formatType   => 'Q',
            artistName   => 'D',
            upc          => 'H',
            albumName    => 'F',
            isrc         => 'L',
            trackName    => 'I',
            units        => 'O',
            price        => 'AB',
            mediaType    => 'Q',
            currencyCode => 'U'
        },
        6 => {
            labelName    => 'E',
            dateBegin    => 'A',
            serviceID    => 'B',
            countryCode  => 'C',
            productType  => 'Q',
            formatType   => 'Q',
            artistName   => 'D',
            upc          => 'H',
            albumName    => 'F',
            isrc         => 'L',
            trackName    => 'I',
            units        => 'O',
            price        => 'AB',
            mediaType    => 'Q',
            currencyCode => 'U'
        },
    );

    return $map{ $self->_version };
}

sub _unverifiedFieldMap { {} };

my %mappings = (
    'T' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type  => RPS::File::Sale::FORMAT_DOWNLOAD,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'S' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type  => RPS::File::Sale::FORMAT_STREAM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'C' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type  => RPS::File::Sale::FORMAT_STREAM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'A' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        format_type  => RPS::File::Sale::FORMAT_DOWNLOAD,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'TD' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type  => RPS::File::Sale::FORMAT_TETHERED,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    '' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type  => RPS::File::Sale::FORMAT_STREAM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
);

sub _headerIdentifier { artistName => 'Artist Name' }

sub currencyCode { shift->{_currencyCode} }

sub serviceID {
    my $self = shift;

    my $service = lc( $self->_getByFieldName('serviceID') || '' );

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

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

sub countryCode {
    my $self = shift;

    my $name = lc( $self->_getByFieldName('countryCode') || 'US' );
    my $service = $self->serviceID || "";

    if ( $name =~ /^(?:\d+|__|--)$/ || $service eq Client::Service::DSP_SOUNDEXCHANGE ) {
        return 'US';
    }

    my %country_mapping = (
        'TU'  => 'TR',  # Turkey
        'PO'  => 'PT',  # Portugal
        'UN'  => 'ZZ',  # Unknown
        'SP'  => 'ES',  # Spain
        'SW'  => 'SE',  # Sweden
        'BU'  => 'BG',  # Bulgaria
        'HO'  => 'HN',  # Honduras
        'PU'  => 'GW',  # Guinea-Bissau
        'IC'  => 'IS',  # Iceland
        'N/A' => 'ZZ', # Unknown
    );

    return $country_mapping{uc($name)} if (exists $country_mapping{uc($name)});

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

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

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 saleDates {
    my $self = shift;

    my $currYear = strftime( '%Y', localtime(time) );

   # YYYY-MM-DD
    my $date = $self->_getByFieldName('dateBegin') || '';
    if ( my ($y, $m, $d) = $date =~ /^(\d{4})[\/.-](\d{1,2})[\/.-](\d{1,2})$/ ) {
        $y = $currYear if $y < 2000 || $y > $currYear;
        $self->fail("Unable to determine dates from: '$date'.") if $m > 12 || $d > 31;
        return $self->_getDates( date_begin =>  sprintf( "%04d-%02d-%02d", $y, $m, $d ) );
    }

    $date = $self->sheetname || $self->filename;

    # MM.DD.YYYY
    if ( my ($m, $d, $y) = $date =~ /(?<!\d)(\d{1,2})[ -._](\d{1,2})[ -._](\d{4})(?:-\d+)?(?:\.\w+)?$/ ) {
        $y = $currYear if $y < 2000 || $y > $currYear;
        $self->fail("Unable to determine dates from: '$date'.") if $m > 12 || $d > 31;
        return $self->_getDates( date_begin => sprintf( "%04d-%02d-%02d", $y, $m, $d ) );
    }
    # MM.YYYY
    elsif ( ($m, $y) = $date =~ /(?<!\d)(\d{1,2})[ -._](\d{4})(?:-\d+)?(?:\.\w+)?$/ ) {
        $y = $currYear if $y < 2000 || $y > $currYear;
        $self->fail("Unable to determine dates from: '$date'.") if $m > 12;
        return $self->_getDates( date_begin => sprintf( "%04d-%02d-01", $y, $m ) );
    }
    # MM.YY
    elsif ( ($m, $y) = $date =~ /(?<!\d)(\d{1,2})[ -._](\d{2})(?:-\d+)?.*$/ ) {
        $y = $currYear if $y < 2000 || $y > $currYear;
        $self->fail("Unable to determine dates from: '$date'.") if $m > 12;
        return $self->_getDates( date_begin => sprintf( "20%02d-%02d-01", $y, $m ) );
    }
    # MmmYY
    elsif ( ($m, $y) = $date =~ /(?<![a-z])(\w{3,9})(\d{2,4}).*$/i ) {
        $m = lc( substr($m, 0, 3) );
        $m = $months{$m} if exists $months{$m};
        $y = sprintf "20%02d", substr($y, -2);
        $y = $currYear if $y < 2000 || $y > $currYear;
        $self->fail("Unable to determine dates from: '$date'.") if !$m || !$y;
        return $self->_getDates( date_begin => sprintf( "20%02d-%02d-01", $y, $m ) );
    }

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

sub productType {
    my $self = shift;

    my $type = uc( $self->_getByFieldName('productType') || '' );

    # RSD-7802
    if ( $self->version == 5 && $type eq 'A' ) {
        return RPS::File::Sale::TYPE_TRACK if $self->isrc;
    }

    return $mappings{$type}{product_type} if exists $mappings{$type};

    $self->handleError( "Unknown product type: '$type'", RPS::DB::Item::SaleImportError::kErrorProductType );
}

sub formatType {
    my $self = shift;

    my $type;
    my $service = $self->serviceID || "";

    if ( $service eq Client::Service::DSP_SOUNDEXCHANGE ) {
        return RPS::File::Sale::FORMAT_PERFORMANCE;
    } else {
        my $formatType = uc( $type = $self->_getByFieldName('formatType') || '' );

        # RSD-7802
        if ( $self->version == 5 && $formatType eq 'A' ) {
            return RPS::File::Sale::FORMAT_STREAM if $self->isrc;
        }

        return $mappings{$formatType}{format_type} if exists $mappings{$formatType};
    }

    $self->handleError( "Unable to determine format type from price category: '$type'", RPS::DB::Item::SaleImportError::kErrorFormatType );
}

sub mediaType {
    my $self = shift;

    my $type = uc( $self->_getByFieldName('mediaType') || '' );

    # RSD-7802
    if ( $self->version == 5 && $type eq 'A' ) {
        return RPS::DB::Item::MediaType::kMediaTypeAudio if $self->isrc;
    }

    return $mappings{$type}{media_type} if exists $mappings{$type};

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

sub isrc {
    my $self = shift;

    my $isrc = $self->_getByFieldName('isrc') || '';
    $isrc =~ s/-//g;

    return $isrc;
}

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;
}

sub _isValidSaleRecord {
    my $self = shift;

    my $date = $self->_getByFieldName("dateBegin") || "";
    $self->fail("No catalog information found. ") if ($date && !($self->artistName || $self->albumName || $self->trackName));

    return defined $self->price && ( $self->trackName || $self->albumName );
}


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

    my $sheetName = $self->sheetname || $self->filename;
    if ( $sheetName =~ /\d{1,2}[ -._](?:\d{2}\.)?\d{2}/i ) {
        return $self->SUPER::_processSheet( $sheet, $sheetnum );
    }
}

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

    $self->SUPER::_preProcess(%args);

    foreach my $line ( @{ $args{lines} } ) {
        $self->{line} = $line;

        my $currencyCode = $self->_getByFieldName('currencyCode') || '';
        if ( $currencyCode =~ /^(\w{3}) Revenue/i ) {
             return $self->{_currencyCode} = $1;
        }
    }

    $self->fail("Unable to get currency code from header");
}

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

1;
