package RPS::Import::Sony::v45;

use strict;
use warnings;

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

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


my %sheetToHeaderMap = (
    'physical sales'   => [ 'physical',  'option1' ],
    'digital sales au' => [ 'digital',   'option1' ],
    'digital sales nz' => [ 'digital',   'option2' ],
    'statement'        => [],    # skip this tab
    'pampd statement'  => [],    # skip this tab
    'transfers au'     => [],    # skip this tab
    'holding fee'      => [],    # skip this tab
);

sub physical {
    shift->dataType eq 'digital' ? 0 : 2;
}

sub _fieldMapExtended {
    {
        physical => {
            # physical sales
            option1 => {
                labelName      => 'C3',
                dateBegin      => 'B',
                dateEnd        => 'B',
                productType    => 'G',
                artistName     => 'D',
                albumName      => 'E',
                wholesalePrice => 'H',
                mediaType      => 'G',
            },
        },
        digital => {
            # digital sales au
            option1 => {
                dateBegin   => 'B',
                dateEnd     => 'B',
                productType => 'F',
                formatType  => 'H',
                artistName  => 'D',
                albumName   => 'E',
                trackName   => 'E',
                units       => 'I',
                price       => 'J',
                mediaType   => 'F',
            },
            # digital sales nz
            option2 => {
                dateBegin   => 'B',
                dateEnd     => 'B',
                productType => 'F',
                formatType  => 'H',
                artistName  => 'D',
                albumName   => 'E',
                trackName   => 'E',
                units       => 'J',
                price       => 'K',
                mediaType   => 'F',
            },
        }
    };
}

sub _unverifiedFieldMapExtended {
    {
        physical => {
            # physical sales
            option1 => {
                _netUnits          => 'P',
                _netValue          => 'U',
                _copyrightPayable  => 'W',
                _returnsFeePayable => 'Y',
                _commissionPayable => 'AA',
            },
        },
        digital => {
            # digital sales au
            option1 => {
                _distFee => 'K',
            },
            # digital sales nz
            option2 => {
                _distFee => 'L',
            },
        }
    };
};

sub _headerIdentifierExtended {
    my $self = shift;

    my $hHeader = {
        physical => {
            option1 => {
                productType => 'Configuration',
            },
        },
        digital => {
            option1 => {
                productType => 'Configuration',
            },
            option2 => {
                productType => 'Configuration',
            },
        }
    };

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


my %mapDigitalProductMedia = (
    'digital audio bundle' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'digital audio extended play' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'digital audio longplay' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'digital audio track' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'digital video track' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'digital video longform' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'digital combo longform' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'mastertone' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'digital maxi single' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'digital combo' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
);

my %mapDigitalFormat = (
    'digital breakage' => {
        format_type => RPS::File::Sale::FORMAT_STREAM,
    },
    'digital download' => {
        format_type => RPS::File::Sale::FORMAT_DOWNLOAD,
    },
    'digital ephemeral' => {
        format_type => RPS::File::Sale::FORMAT_EPHEMERAL,
    },
    'digital locker play' => {
        format_type => RPS::File::Sale::FORMAT_STREAM,
    },
    'digital locker stream' => {
        format_type => RPS::File::Sale::FORMAT_STREAM,
    },
    'digital stream ad supp' => {
        format_type => RPS::File::Sale::FORMAT_STREAM,
    },
    'digital stream subscription' => {
        format_type => RPS::File::Sale::FORMAT_STREAM,
    },
);

my %sheetRules = (
    'physical sales' => {
        countryCode  => 'AU',
        currencyCode => 'AUD',
        channel      => RPS::File::Sale::CHANNEL_RETAIL,
        priceLevel   => RPS::File::Sale::PLEVEL_UNKNOWN,
        productType  => sub {
            return RPS::File::Sale::TYPE_CD         if $_[1] =~ qr/^CD Album$/i;
            return RPS::File::Sale::TYPE_DVD_CD_SET if $_[1] =~ qr/^CD\/DVD Combo$/i;
            return RPS::File::Sale::TYPE_LP         if $_[1] =~ qr/^Vinyl Album$/i;
        },
        mediaType => sub {
            return RPS::DB::Item::MediaType::kMediaTypeVideo if $_[1] =~ qr/^CD\/DVD Combo$/i;
            return RPS::DB::Item::MediaType::kMediaTypeAudio if $_[1] =~ qr/^(?:CD|Vinyl) Album$/i;
        },
        totalRevenue => sub {
            my $netValue          = $_[0]->_getByFieldName('_netValue')          || 0;
            my $copyrightPayable  = $_[0]->_getByFieldName('_copyrightPayable')  || 0;
            my $returnsFeePayable = $_[0]->_getByFieldName('_returnsFeePayable') || 0;
            my $commissionPayable = $_[0]->_getByFieldName('_commissionPayable') || 0;
            return $netValue - $copyrightPayable - $returnsFeePayable - $commissionPayable;
        },
    },
    'digital sales au' => {
        serviceID    => Client::Service::DSP_SONY,
        countryCode  => 'AU',
        currencyCode => 'AUD',
        productType  => sub {
            return $mapDigitalProductMedia{ $_[1] }{product_type} if exists $mapDigitalProductMedia{ $_[1] };
        },
        mediaType => sub {
            return $mapDigitalProductMedia{ $_[1] }{media_type} if exists $mapDigitalProductMedia{ $_[1] };
        },
        formatType => sub {
            return $mapDigitalFormat{ $_[1] }{format_type} if exists $mapDigitalFormat{ $_[1] };
        },
        albumName => sub {
            return $_[0]->productType eq RPS::File::Sale::TYPE_ALBUM ? $_[1] : '';
        },
        trackName => sub {
            return $_[0]->productType eq RPS::File::Sale::TYPE_TRACK ? $_[1] : '';
        },
        price => sub {
            my $distFee = $_[0]->_getByFieldName('_distFee') || 0;
            return $_[1] * (1 - $distFee);
        }
    },
    'digital sales nz' => {
        serviceID    => Client::Service::DSP_SONY,
        countryCode  => 'NZ',
        currencyCode => 'NZD',
        productType  => sub {
            return $mapDigitalProductMedia{ $_[1] }{product_type} if exists $mapDigitalProductMedia{ $_[1] };
        },
        mediaType => sub {
            return $mapDigitalProductMedia{ $_[1] }{media_type} if exists $mapDigitalProductMedia{ $_[1] };
        },
        formatType => sub {
            return $mapDigitalFormat{ $_[1] }{format_type} if exists $mapDigitalFormat{ $_[1] };
        },
        albumName => sub {
            return $_[0]->productType eq RPS::File::Sale::TYPE_ALBUM ? $_[1] : '';
        },
        trackName => sub {
            return $_[0]->productType eq RPS::File::Sale::TYPE_TRACK ? $_[1] : '';
        },
        price => sub {
            my $distFee = $_[0]->_getByFieldName('_distFee') || 0;
            return $_[1] * (1 - $distFee);
        }
    },
);

sub saleDates {
    my $self = shift;

    # YYYYMM
    my $dateBegin = $self->_getByFieldName('dateBegin') || '';
    if ( $dateBegin =~ /^(\d{4})(\d{2})$/i ) {
        return
            sprintf("%04d-%02d-%02d", $1, $2, 1),
            sprintf("%04d-%02d-%02d", $1, $2, Date::Calc::Days_in_Month( $1, $2 ));
    }

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

sub serviceID {
    my $self = shift;

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

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

    return $serviceID if $serviceID;
}

sub labelName {
    my $self = shift;

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

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

sub countryCode {
    my $self = shift;

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

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

sub productType {
    my $self = shift;

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

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

sub artistName {
    my $self = shift;

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

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

sub albumName {
    my $self = shift;

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

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

sub trackName {
    my $self = shift;

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

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

sub channel {
    my $self = shift;

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

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

sub priceLevel {
    my $self = shift;

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

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

sub currencyCode  {
    my $self = shift;

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

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

sub wholesalePrice {
    my $self = shift;

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

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

sub mediaType {
    my $self = shift;

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

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

sub formatType {
    my $self = shift;

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

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


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


# physical
sub netUnits {
    my $self = shift;

    my $netUnits = $self->_getByFieldName('_netUnits') || 0;
    return $self->totalRevenue >= 0 ? abs($netUnits) : abs($netUnits) * -1;
}

sub totalRevenue {
    my $self = shift;

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

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

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 }


# internal
sub _isValidSaleRecord {
    my $self = shift;

    if ( $self->dataType =~ /physical/i ) {
        return ($self->artistName || $self->albumName) && $self->productType;
    }

    return ( $self->_getByFieldName('trackName') || $self->_getByFieldName('albumName') || $self->_getByFieldName('artistName') );
}

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() || '';
    $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 ) = @_;

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

    $self->fail( "Encountered unrecognized sheet '$self->{sheetname}'" );
}


1;