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

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

    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->_getByFieldName('units');
    $self->{_detailUnits} += $units;

    my $price = $self->_getByFieldName('price');
    $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.
###
