package RPS::Import::Universal::v66;

use strict;
use warnings;

use lib '/app/tools/rps/lib';
use RPS::File::Sale;
use RPS::Import::ServiceMap;
use RPS::DB::Item::MediaType;
use Date::Calc qw(Days_in_Month Add_Delta_Days Decode_Month);

use parent 'RPS::Import::MapFaceBase';
use parent 'RPS::Import::ImporterMixed';

sub physical { 2 }

sub _fieldMapExtended {
    {
        mixed => {
            option1 => {
                labelName    => 'C',
                serviceID    => 'P',
                countryCode  => 'R',
                dateBegin    => 'K',
                dateEnd      => 'L',
                productType  => 'U',
                formatType   => 'Z',
                artistName   => 'W',
                upc          => 'T',
                albumName    => 'X',
                isrc         => 'T',
                trackName    => 'X',
                units        => 'AB',
                channel      => 'Z',
                free         => 'Z',
                totalRevenue => 'BE',
                price        => 'BE',
                mediaType    => 'U',
            },
        },
    };
}

sub _unverifiedFieldMapExtended {
    {
        mixed => {
            option1 => {
                _ppdPrice     => 'AG',
                _retailPrice  => 'AE',
                _exchangeRate => 'AV',
                netUnits      => 'AB',
            },
        }
    };
}

sub _headerIdentifierExtended {
    {
        mixed => {
            option1 => { upc => 'Item ID' }
        },
    };
}

my %typeMap = (
    '5CD' => {
        product_type => RPS::File::Sale::TYPE_CD,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    '12LP33' => {
        product_type => RPS::File::Sale::TYPE_LP,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    '10SP33' => {
        product_type => RPS::File::Sale::TYPE_LP5,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    '12MS33' => {
        product_type => RPS::File::Sale::TYPE_LP5,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    '7SP45' => {
        product_type => RPS::File::Sale::TYPE_LP5,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    '10LP45' => {
        product_type => RPS::File::Sale::TYPE_LP,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ELP' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ESP' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'EAAHD' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ESPMT' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ETRACK' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'EVIDEO' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'ESAMTHD' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
);

my %quarters = (
    1 => { begin_month => 1,  end_month => 3  },
    2 => { begin_month => 4,  end_month => 6  },
    3 => { begin_month => 7,  end_month => 9  },
    4 => { begin_month => 10, end_month => 12 },
);

sub currencyCode { 'USD' }
sub priceLevel   { RPS::File::Sale::PLEVEL_UNKNOWN }

sub serviceID {
    my $self = shift;

    my $service = lc( $self->_getByFieldName('serviceID') // '' );
    return Client::Service::DSP_UNIVERSAL if $service eq 0;

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

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

sub countryCode   {
    my $self = shift;

    my $name = $self->_getByFieldName('countryCode') || '';
    my $oCountry = Common::Country->Get($name);

    return $oCountry ? $oCountry->alpha2() : $name;
}

sub saleDates {
    my $self = shift;

    my $dateBegin = $self->_getByFieldName('dateBegin') || '';
    my $dateEnd   = $self->_getByFieldName('dateEnd')   || '';

    $dateBegin = $self->_getDateByQuarter($dateBegin, 'begin');
    $dateEnd   = $self->_getDateByQuarter($dateEnd, 'end');

    return $dateBegin, $dateEnd;
}

sub _getDateByQuarter {
    my ($self, $date, $flag) = @_;

    my ($year, $quarter);
    unless ( ($year, $quarter) = $date =~ /(\d{4})(\d)/ ) {
        $self->fail( "Unable to determine date" . ucfirst($flag) . "period: '$date'." );
    }

    if ( !exists $quarters{$quarter} || !exists $quarters{$quarter}{$flag . '_month'} ) {
        $self->fail( "Invalid quarter value: $quarter." );
    }

    my $month = $quarters{$quarter}{$flag . '_month'};
    my $day   = $flag eq 'begin' ? 1 : Days_in_Month( $year, $month);
    $date = sprintf "%04d-%02d-%02d", $year, $month, $day;

    return $date if $date =~ /^\d{4}-\d{2}-\d{2}$/;

    $self->fail( "Unable to determine date" . ucfirst($flag) . "period: '$date'." );
}

sub productType {
    my $self = shift;

    my $type = uc( $self->_getByFieldName('productType') || '' );
    if ( exists $typeMap{$type} && exists $typeMap{$type}{product_type} ) {
        return $typeMap{$type}{product_type};
    }

    return $self->handleError(
        "Product type not set: $type",
        RPS::DB::Item::SaleImportError::kErrorNonqualifying
    );
}

sub formatType {
    my $self = shift;

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

    return RPS::File::Sale::FORMAT_STREAM if $type =~ /^
        Ad.+Streaming | Cloud.+Service | Digital.+Streaming\) | Mobile.+tones
    $/xi;

    return RPS::File::Sale::FORMAT_PERFORMANCE if $type =~ /^
        Broadcasting.+share\) | Clip.+share\) | Neighboring.+share\) | Performance.+only\)
    $/xi;

    return RPS::File::Sale::FORMAT_DOWNLOAD if $type =~ /^
        Digital.+Downloads\) | Permanent.+Download | Permanent.+subscription\) | Streaming.+subscription\)
    $/xi;

    return RPS::File::Sale::FORMAT_RINGTONE if $type =~ /^ Ring.+masters\) $/xi;

    if ( $type =~ /^Synchronization.+Fees$/xi ) {
        $self->handleError(
            "Product format error: '$type'",
            RPS::DB::Item::SaleImportError::kErrorNonqualifying
        );
    }

    return $self->handleError(
        "Couldn't determine product format '$type': ",
        RPS::DB::Item::SaleImportError::kErrorFormatType
    );
}

sub upc {
    my $self = shift;

    my $isDigitalProduct = $self->isDigitalProduct( $self->productType );
    return !$isDigitalProduct || $self->productType eq RPS::File::Sale::TYPE_ALBUM
        ? $self->_getByFieldName('upc')
        : undef;
}

sub isrc {
    my $self = shift;

    return $self->productType eq RPS::File::Sale::TYPE_TRACK
        ? (my $isrc) = ($self->_getByFieldName('isrc') || '') =~ /^\w(.+)$/
        : undef;
}

sub albumName {
    my $self = shift;

    return $self->productType eq RPS::File::Sale::TYPE_ALBUM
        ? $self->_getByFieldName('albumName')
        : undef;
}

sub trackName {
    my $self = shift;

    return $self->productType eq RPS::File::Sale::TYPE_TRACK
        ? $self->_getByFieldName('trackName')
        : undef;
}

sub channel {
    my $self = shift;

    my $channel = $self->_getByFieldName('channel') || '';
    return RPS::File::Sale::CHANNEL_RETAIL if $channel =~ /^
        Cutout\/Deletion | Normal.+Sales | Normal.+advertise | Promo.+stock | Standard.+Goods
    $/xi;

    return RPS::File::Sale::CHANNEL_DIRECT if $channel =~ /^ Direc.+DC $/xi;

    $self->fail("Unsupported sales channel for physical product type: '$channel'.");
}

sub wholesalePrice {
    my $self = shift;

    my $ppdPrice = $self->_getByFieldName('_ppdPrice')         || 0;
    my $exchangeRate = $self->_getByFieldName('_exchangeRate') || 0;

    return $ppdPrice * $exchangeRate;
}

sub retail {
    my $self = shift;

    my $retailPrice  = $self->_getByFieldName('_retailPrice')  || 0;
    my $exchangeRate = $self->_getByFieldName('_exchangeRate') || 0;

    return ! $self->isDigitalProduct( $self->productType )
        ? $retailPrice * $exchangeRate
        : undef;
}

sub free {
    my $self = shift;

    my $free  = $self->_getByFieldName('free')  || '';
    my $price = $self->_getByFieldName('price') || 0;
    return if $price;

    return 1 if $free =~ /^ Standard.+Goods | Promo.+stock $/xi;
}

sub mediaType {
    my $self = shift;

    my $type = uc( $self->_getByFieldName('mediaType') || '' );
    if ( exists $typeMap{$type} && exists $typeMap{$type}{media_type} ) {
        return $typeMap{$type}{media_type};
    }

    return $self->handleError(
        "Media type not set: '$type'",
        RPS::DB::Item::SaleImportError::kErrorNonqualifying
    );
}

sub price     { abs( shift->_getByFieldName('price') || 0 ) }
sub unitPrice { abs shift->SUPER::unitPrice }
sub units {
    my $self = shift;

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

    return $price < 0 ? abs($units) * -1 : $units;
}

sub netUnits       { sprintf "%.0f", ( shift->_getByFieldName('netUnits') || 0 ) }
sub totalRevenue   { $_[0]->_getByFieldName('totalRevenue')               || 0 }
sub sales          { $_[0]->netUnits     > 0 ? $_[0]->netUnits         : 0 }
sub salesRevenue   { $_[0]->totalRevenue > 0 ? $_[0]->totalRevenue     : 0 }
sub returns        { $_[0]->netUnits     < 0 ? abs $_[0]->netUnits     : 0 }
sub returnsRevenue { $_[0]->totalRevenue < 0 ? abs $_[0]->totalRevenue : 0 }

sub _isValidSaleRecord {
    my $self = shift;

    return $self->netUnits && defined $self->totalRevenue && $self->_getByFieldName('albumName');
}

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

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

    return if $self->{sheetname} !~ /^FULL DATA$/i;
    return $self->SUPER::_processSheet($sheet, $sheetnum);
}


1;
