package RPS::Import::RSDigitalFmt3;

use strict;

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

use lib '/app/tools/data_classes/lib';
use File::Sale;

use lib '/app/tools/rps/lib';
use RPS::Import::SaleRec;
use RPS::Import::ServiceMap;
use base 'RPS::Import::MapFaceBase';
use base 'RPS::Import::Importer';

sub _fieldMap {
    my $self    = shift;
    my $version = $self->_version;

    my %field_map = (
        3 => {

            # header
            serviceID    => 'B1',
            currencyCode => 'H',

            # detail
            labelName        => 'A',
            countryCode      => 'B',
            productType      => 'E',
            formatType       => 'F',
            mediaType        => 'G',
            serviceProductID => 'H',
            clientProductID  => 'I',
            artistName       => 'J',
            upc              => 'L',
            albumName        => 'M',
            isrc             => 'N',
            trackNum         => 'O',
            trackName        => 'P',
            units            => 'Q',
            price            => 'T',
        },
        4 => {

            # header
            currencyCode => 'F',

            # detail
            serviceID        => 'A',
            labelName        => 'B',
            countryCode      => 'C',
            productType      => 'F',
            formatType       => 'G',
            mediaType        => 'H',
            serviceProductID => 'I',
            clientProductID  => 'J',
            artistName       => 'K',
            upc              => 'M',
            albumName        => 'N',
            isrc             => 'O',
            trackNum         => 'P',
            trackName        => 'Q',
            units            => 'R',
            price            => 'U',
        },
        5 => {

            # header
            currencyCode => 'F',

            # detail
            serviceID        => 'A',
            labelName        => 'B',
            countryCode      => 'C',
            productType      => 'F',
            formatType       => 'G',
            mediaType        => 'H',
            serviceProductID => 'I',
            clientProductID  => 'J',
            artistName       => 'K',
            upc              => 'M',
            albumName        => 'N',
            isrc             => 'O',
            trackNum         => 'P',
            trackName        => 'Q',
            units            => 'R',
            price            => 'U',
            free             => 'V',
        },
        6 => {
            # header
            currencyCode => 'F',

            # detail
            labelName        => 'B',
            serviceID        => 'A',
            countryCode      => 'C',
            productType      => 'F',
            formatType       => 'G',
            serviceProductID => 'I',
            clientProductID  => 'L',
            artistName       => 'K',
            upc              => 'M',
            albumName        => 'N',
            isrc             => 'O',
            trackNum         => 'P',
            trackName        => 'Q',
            units            => 'R',
            currencyCode     => 'F',
            free             => 'U',
            grossRevenue     => 'S',
            price            => 'T',
            mediaType        => 'H',
        },
    );
    return $field_map{$version};
}

sub _unverifiedFieldMap {
    my $self    = shift;
    my $version = $self->_version;

    my %field_map = (
        3 => {

            # header
            totalUnits => 'D',
            totalPrice => 'F',

            # detail
            year  => 'C',
            month => 'D',
        },
        4 => {

            # header
            totalUnits => 'B',
            totalPrice => 'D',

            # detail
            year  => 'D',
            month => 'E',
        },
        5 => {

            # header
            totalUnits => 'B',
            totalPrice => 'D',

            # detail
            year         => 'D',
            month        => 'E',
            royalty_type => 'W',
        },
        6 => {
            # header
            totalUnits => 'B',
            totalPrice => 'D',

            # detail
            year         => 'D',
            month        => 'E',
        },

    );
    return $field_map{$version};
}

sub _headerIdentifier { ( labelName => 'label-name' ) }

sub serviceID {
    my $self    = shift;
    my $version = $self->_version;

    # From the header; see _processSheet().
    #
    return $self->{_serviceID} if ( $version == 3 && defined $self->{_serviceID} );

    # Note: for an unknown service in version 3, the serviceID lookup is redundant
    # because it would have failed earlier in _processSheet().
    #
    my $serviceName = ( $version == 3 ) ? $self->{_serviceName} : $self->_getByFieldName('serviceID');

    if ( !$serviceName || '' eq $serviceName ) {
        return $self->handleError( "Error: service-name cannot be blank.", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
    }

    return Client::Service::DSP_SOUNDEXCHANGE if ( $serviceName =~ /^SOUNDEXCHANGE ARTIST SHARE 1$/i );

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

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

# The file header spans two lines.  The first line contains the summary data (units,
# revenue, currency code, and maybe the service).  The second line is the header for
# the detail lines.
#
sub _processSheet {
    my $self     = shift;
    my $sheet    = shift;
    my $sheetnum = shift;
    my $version  = $self->_version;

    my $headerUnits;
    my $headerRevenue;

    # Reset our custom attributes for each sheet
    #

    # These are from the header
    #
    $self->{_currencyCode} = undef;
    $self->{_totalUnits}   = 0;
    $self->{_totalPrice}   = 0;
    $self->{_serviceID}    = undef;
    $self->{_serviceName}  = undef;

    # These are the revenue and unit sums for the detail lines on each sheet
    #
    $self->{_totalRoyalty} = 0;
    $self->{_detailUnits}  = 0;

    my $headerUnits;
    my $headerRevenue;

    foreach my $line (@$sheet) {
        $self->{line} = $line;
        my ( $service_id, $total_units, $total_price, $currency_code );

        $headerUnits   = $self->_getByFieldName('totalUnits') || 0;
        $headerRevenue = $self->_getByFieldName('totalPrice') || 0;
        $currency_code = $self->_getByFieldName('currencyCode');

        $self->{_currencyCode} = $currency_code;

        next if ( !$headerUnits );

        if ( $version == 3 ) {
            my $serviceName = $self->_getByFieldName('serviceID');

            if ( !$serviceName || '' eq $serviceName ) {
                return $self->handleError( "Error: service-name cannot be blank.", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
            }

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

            # Abort the import if the service can't be determined from the header.
            # We can't defer this to MapFace because MF is geared towards resolving
            # errors in the sales lines, not the header
            #
            if ( !$serviceID ) {
                $self->{_serviceName} = $serviceName;
            } else {
                $self->{_serviceID} = $serviceID;
            }
        }

        last;    # only look at the first line
    }

    # Skip the sheet if there aren't any units being reported
    #
    return if ( !$headerUnits );

    # Process the detail lines
    #
    $self->RPS::Import::Importer::_processSheet( $sheet, $sheetnum );

    # Validate the totals
    #
    my $totalRoyalty = $self->{_totalRoyalty};    # See price()
    my $totalUnits   = $self->{_detailUnits};     # See units()

    # Check the total units and total royalty.  Note: we round to two
    # decimal places for comparison purposes.
    #
    $headerRevenue = sprintf( "%.2f", $headerRevenue );
    $totalRoyalty  = sprintf( "%.2f", $totalRoyalty );

    # Check to ensure the header matches aggregate count
    unless ( $totalRoyalty == $headerRevenue || $totalRoyalty eq $headerRevenue ) {
        $self->errstr("Header Royalty ($headerRevenue) / detail royalty-total ($totalRoyalty) mismatch");
        return undef;
    }

    unless ( $totalUnits == $headerUnits ) {
        $self->errstr("Header Units / detail units mismatch");
        return undef;
    }
}

sub currencyCode {
    my $self = shift;
    return $self->{_currencyCode};    # From header; see _processHeader()
}

sub countryCode {
    my $self = shift;
    my $name = $self->_getByFieldName('countryCode');

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

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

sub _isValidSaleRecord {
    my $self = shift;

    return ( defined $self->units && ( $self->trackName || $self->albumName || $self->artistName || $self->upc ) );
}

sub units {
    return shift->_getByFieldName('units') || 0;
}

sub upc {
    my $self = shift;
    my $upc  = $self->_getByFieldName('upc');
    $upc =~ s/[^0-9]//g;
    return $upc;
}

sub isrc {
    my $self = shift;
    my $isrc = $self->_getByFieldName('isrc');
    $isrc = normalize_isrc($isrc);
    return $isrc;
}

sub trackName {
    my $self  = shift;
    my $title = $self->_getByFieldName('trackName');
    return $title;
}

sub trackNum {
    my $self = shift;
    my $num  = $self->_getByFieldName('trackNum');
    return $num;
}

sub artistName {
    my $self  = shift;
    my $name = $self->_getByFieldName('artistName') || "";

    $self->fail("Artist name is not defined.") if ($self->_version == 5 && ($self->units && !$name));

    return $name;

}

sub productType {

    my $self           = shift;
    my $f_product_type = $self->_getByFieldName('productType');

    my %product_type_map = (
        "a" => RPS::File::Sale::TYPE_ALBUM,
        "t" => RPS::File::Sale::TYPE_TRACK
    );

    my $product_type = $product_type_map{ lc $f_product_type };

    return $product_type if ($product_type);

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

sub formatType {
    my $self       = shift;
    my $f_format   = $self->_getByFieldName('formatType');
    my %format_map = (
        "d"     => RPS::File::Sale::FORMAT_DOWNLOAD,
        "dp"    => RPS::File::Sale::FORMAT_DOWNLOADPREMIUM,
        "du"    => RPS::File::Sale::FORMAT_DOWNLOADUPGRADE,
        "dd"    => RPS::File::Sale::FORMAT_DUALDOWNLOAD,
        "dteth" => RPS::File::Sale::FORMAT_TETHERED,
        "vpd"   => RPS::File::Sale::FORMAT_VPD,
        "ring"  => RPS::File::Sale::FORMAT_RINGTONE,
        "ds"    => RPS::File::Sale::FORMAT_STREAM,
        "bg"    => RPS::File::Sale::FORMAT_BACKGROUNDMUSIC,
        "jb"    => RPS::File::Sale::FORMAT_JUKEBOX,
        "pi"    => RPS::File::Sale::FORMAT_PERFORMANCE,
        "eph"   => RPS::File::Sale::FORMAT_EPHEMERAL,
        "n-eph" => RPS::File::Sale::FORMAT_NON_EPHEMERAL
    );

    my $format = $format_map{ lc $f_format };
    return $format if ($format);

    return $self->handleError( "Unknown format type '$f_format'", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
}

sub mediaType {
    my $self         = shift;
    my $f_media_type = $self->_getByFieldName('mediaType');

    # We are going to default this to Audio (if it's blank )for the legacy versions of the template.
    my $version = $self->_version;
    if ( !$f_media_type && ( $version == 3 || $version == 4 ) ) {
        return RPS::DB::Item::MediaType::kMediaTypeAudio;
    }

    my %media_type_map = (
        "a" => RPS::DB::Item::MediaType::kMediaTypeAudio,
        "v" => RPS::DB::Item::MediaType::kMediaTypeVideo
    );
    my $media_type = $media_type_map{ lc $f_media_type };
    return $media_type if ($media_type);

    return $self->handleError( "Unknown media type '$f_media_type'", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
}

sub saleDates {
    my $self   = shift;
    my $month  = $self->_getByFieldName('month');
    my $year   = $self->_getByFieldName('year');
    my $f_date = sprintf( "%4d-%02d-%02d", $year, $month, 01 );

    return $self->_getDates( date_begin => $f_date, type => 'iso' );
}

sub free {
    my $self = shift;
    my $free = 0;

    if ( exists $self->_fieldMap->{'free'} ) {
        my $_free = $self->_getByFieldName('free');
        my $price = $self->_getByFieldName('price');

        $free = ( uc $_free eq 'Y' ) ? 1 : 0;

        if ( $free == 1 && $price != 0 ) {
            $self->errstr( "Line " . $self->linenum . ": Revenue must be 0 for free sales" );
            return undef;
        }
    }
    return $free;
}

sub _processLine {
    my $self = shift;

    # Tally the units and price before we process the line
    #
    my $units = $self->units;
    my $price = $self->_getByFieldName('price');

    if ( $price && !$units ) {
        $self->errstr( "Units are required for all sales. No units entered on line: " . $self->linenum );
    }

    $self->{_detailUnits} += $units;
    $self->{_totalRoyalty} += $price;

    # Process flagging data (if any)
    # Note that UK Mech is excluded here, since it is physical-only.
    #
    if ( exists $self->_unverifiedFieldMap->{'royalty_type'} ) {
        my $royaltyType = uc $self->_getByFieldName('royalty_type');

        # Reset the flags for each line.  "0" means sale is imported normally
        # and will be available for processing in all types of royalty runs.
        #
        $self->{_usMechStatus} = 0;
        $self->{_caMechStatus} = 0;
        $self->{_labelStatus}  = 0;
        $self->{_artistStatus} = 0;

        if ( $royaltyType && 'ALL' ne $royaltyType ) {

            # Turn -off- all the types, and only enable those that were specified.
            #
            $self->{_usMechStatus} = 2;
            $self->{_caMechStatus} = 2;
            $self->{_labelStatus}  = 2;
            $self->{_artistStatus} = 2;

            my @types = split( ' ', $royaltyType );
            foreach my $type (@types) {
                my $testType = uc($type);
                if ( 'ARTIST' eq $testType ) {
                    $self->{_artistStatus} = 0;
                } elsif ( 'LABEL' eq $testType ) {
                    $self->{_labelStatus} = 0;
                } elsif ( 'US-MECH' eq $testType ) {
                    $self->{_usMechStatus} = 0;
                } elsif ( 'CA-MECH' eq $testType ) {
                    $self->{_caMechStatus} = 0;
                } else {
                    $self->errstr( "invalid royalty type (" . $royaltyType . "): line " . $self->linenum );
                    return undef;
                }
            }
        }
    }

    return $self->SUPER::_processLine(@_);
}

sub mechanicalRoyaltyStatus {
    my $self = shift;
    return $self->{_usMechStatus};
}

sub caMechanicalRoyaltyStatus {
    my $self = shift;
    return $self->{_caMechStatus};
}

sub artistRoyaltyStatus {
    my $self = shift;
    return $self->{_artistStatus};
}

sub labelRoyaltyStatus {
    my $self = shift;
    return $self->{_labelStatus};
}

# We'll set a couple of extra SaleRec fields before continuing on with
# the normal _insertSale
#
sub _insertSale {
    my $self = shift;
    my %args = @_;

    my $saleRec = $args{sale};

    $saleRec->mechanical_royalty_status( $self->mechanicalRoyaltyStatus );
    $saleRec->ca_mechanical_royalty_status( $self->caMechanicalRoyaltyStatus );
    $saleRec->artist_royalty_status( $self->artistRoyaltyStatus );
    $saleRec->label_royalty_status( $self->labelRoyaltyStatus );

    $self->SUPER::_insertSale( sale => $saleRec );
}

#####    MapFace    #####
#
sub _mapFaceCompatibleVersions {
    return ( 3, 4, 5 );
}

sub _mapFaceServiceID {
    return ('serviceID');
}

# Service ID is the only mappable field for this importer.

sub _mapFaceCountryCode { }

sub _mapFaceProductType { }

sub _mapFaceFormatType { }

sub _mapFaceMediaType { }

###
1;    # Play nicely.
###
