package RPS::Import::RSPhysicalFormat;

use strict;

use Date::Calc qw(Days_in_Month Decode_Month);

use lib '/app/tools/common/lib';
use Common::Util qw(normalize_date normalize_isrc);
use Common::Consts qw(%COUNTRY_CODE %CODE_TO_COUNTRY);
use Common::RSMath qw(round);

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

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

my %fieldMap = (
    5 => {
        'label'       => 0,
        'country'     => 1,
        'year'        => 2,
        'month'       => 3,
        'format'      => 4,
        'artist'      => 5,
        'catno'       => 6,
        'upc'         => 7,
        'album'       => 8,
        'channel'     => 9,
        'price_level' => 10,

        'wholesale_price' => 11,
        'retail_price'    => 12,

        'sales'       => 13,
        'sales_price' => 14,

        'returns'       => 15,
        'returns_price' => 16,

        'net_units' => 17,
        'net_price' => 18,

        'free'         => 19,
        'adjustment'   => 20,
        'royalty_type' => 21,
        'comments'     => 22,
    },
    6 => {
        'label'           => 0,
        'country'         => 1,
        'year'            => 2,
        'month'           => 3,
        'format'          => 4,
        'artist'          => 5,
        'catno'           => 6,
        'upc'             => 7,
        'album'           => 8,
        'channel'         => 9,
        'price_level'     => 10,

        'wholesale_price' => 11,
        'retail_price'    => 12,

        'sales'           => 999,  # not presented
        'sales_price'     => 999,  # not presented

        'returns'         => 999,  # not presented
        'returns_price'   => 999,  # not presented

        'net_units'       => 13,
        'gross_revenue'   => 14,
        'net_price'       => 15,

        'free'            => 16,
        'adjustment'      => 999,  # not presented
        'royalty_type'    => 999,  # not presented
        'comments'        => 999,  # not presented
    },
);

my %channelMap = (
    retail       => RPS::File::Sale::CHANNEL_RETAIL,
    military     => RPS::File::Sale::CHANNEL_MILITARY,
    px           => RPS::File::Sale::CHANNEL_MILITARY,
    club         => RPS::File::Sale::CHANNEL_CLUB,
    'mail order' => RPS::File::Sale::CHANNEL_MAILORDER,
    direct       => RPS::File::Sale::CHANNEL_DIRECT
);

#public methods

sub _importLines {
    my $self = shift;
    my %args = @_;

    my $lines   = $args{lines};
    my $fileObj = $args{file};
    my $version = $self->_version;

    my $totalRevenue = 0;
    my $totalUnits   = 0;

    return undef unless ( defined $lines && defined $version );

    my $offsets;

    if ( exists $fieldMap{$version} ) {
        $offsets = $fieldMap{$version};
    } else {
        $self->errstr('wrong version');
        return 0;
    }

    my ( $serviceID, $headerUnits, $headerRevenue, $currencyCode ) = $self->_readHeader( $lines->[0] );

    unless ( $headerUnits && $headerRevenue && $currencyCode ) {
        $self->errstr("Unrecognized header, line: 1");
        return undef;
    }

    unless ($serviceID) {
        $self->errstr("Unknown service: '$lines->[0]->[1]'");
        return undef;
    }

    my $linenum = 3;
    shift @$lines;    ## skip header
    shift @$lines;    ## skip header line 2

    foreach my $line (@$lines) {
        unless ( $line->[ $offsets->{label} ]
            || $line->[ $offsets->{country} ]
            || $line->[ $offsets->{net_units} ]
            || $line->[ $offsets->{net_price} ] ) {
            $linenum++;
            next;
        }

        my $channel = RPS::File::Sale::CHANNEL_RETAIL;

        my $c = lc $line->[ $offsets->{channel} ];
        $channel = $channelMap{$c};
        unless ( defined $channel ) {
            $self->errstr("unknown channel: $c");
            return undef;
        }

        my $priceLevel = RPS::File::Sale::PLEVEL_UNKNOWN;

        my $p = lc $line->[ $offsets->{price_level} ];

        # RSD-5575: Switched UNKNOWN price level to error out if column has digital value
        $self->fail("Wrong price level: '$p'") if ($p =~ /^\d+/);

        if ( $p eq 'unknown' ) {
            $priceLevel = RPS::File::Sale::PLEVEL_UNKNOWN;
        } elsif ( $p eq 'full' ) {
            $priceLevel = RPS::File::Sale::PLEVEL_FULL;
        } elsif ( $p =~ m/^mid(line)?$/ ) {
            $priceLevel = RPS::File::Sale::PLEVEL_MID;
        } elsif ( $p eq 'budget' ) {
            $priceLevel = RPS::File::Sale::PLEVEL_BUDGET;
        } elsif ( $p eq 'promo' ) {
            $priceLevel = RPS::File::Sale::PLEVEL_PROMO;
        } else {
            $self->errstr("unknown price level: $p");
        }

        my ( $config, $productType );

        if ( $line->[ $offsets->{format} ] =~ m/^dvd$/i ) {
            $config      = "DVD";
            $productType = RPS::File::Sale::TYPE_DVD;
        } elsif ( $line->[ $offsets->{format} ] =~ m/^cd$/i ) {
            $config      = "CD";
            $productType = RPS::File::Sale::TYPE_CD;
        } elsif ( $line->[ $offsets->{format} ] =~ m/^lp$/i ) {
            $config      = "LP";
            $productType = RPS::File::Sale::TYPE_LP;
        } elsif ( $line->[ $offsets->{format} ] =~ m/^lp5$/i ) {
            $config      = "LP5";
            $productType = RPS::File::Sale::TYPE_LP5;
        } elsif ( $line->[ $offsets->{format} ] =~ m/^bd$/i ) {
            $config      = "BD";
            $productType = RPS::File::Sale::TYPE_BLURAY;
        } elsif ( $line->[ $offsets->{format} ] =~ m/^ep$/i ) {
            $config      = "EP";
            $productType = RPS::File::Sale::TYPE_EP;
        } elsif ( $line->[ $offsets->{format} ] =~ m/^cd2$/i ) {
            $config      = "CD2";
            $productType = RPS::File::Sale::TYPE_DBL_CD;
        } elsif ( $line->[ $offsets->{format} ] =~ m/^2cd$/i ) {
            $config      = "CD2";
            $productType = RPS::File::Sale::TYPE_DBL_CD;
        } elsif ( $line->[ $offsets->{format} ] =~ m/^vhs$/i ) {
            $config      = "VHS";
            $productType = RPS::File::Sale::TYPE_VHS;
        } elsif ( $line->[ $offsets->{format} ] =~ /CD\/DVD/i ) {
            $config      = "DVD/CD";
            $productType = RPS::File::Sale::TYPE_DVD_CD_SET;
        } elsif ( $line->[ $offsets->{format} ] =~ /DVDCD/i ) {
            $config      = "DVD/CD";
            $productType = RPS::File::Sale::TYPE_DVD_CD_SET;
        } elsif ( $line->[ $offsets->{format} ] =~ /cass/i ) {
            $config      = "CASS";
            $productType = RPS::File::Sale::TYPE_CASS;
        } elsif ( $line->[ $offsets->{format} ] =~ /cas5/i ) {
            $config      = "CAS5";
            $productType = RPS::File::Sale::TYPE_CAS_SIN;
        } elsif ( $line->[ $offsets->{format} ] =~ /CD5/i ) {
            $config      = "CD5";
            $productType = RPS::File::Sale::TYPE_CD_SIN;
        } else {
            $self->errstr( "unknown format: " . $line->[ $offsets->{format} ] );
            return undef;
        }

        my $catno  = $line->[ $offsets->{catno} ];
        my $label  = $line->[ $offsets->{label} ];
        my $artist = $line->[ $offsets->{artist} ];
        my $album  = $line->[ $offsets->{album} ];
        my $upc    = $line->[ $offsets->{upc} ];

        my $countryCode;
        if ( $line->[ $offsets->{country} ] =~ m/^\w\w$/ ) {
            $countryCode = uc $line->[ $offsets->{country} ];
            $countryCode = 'GB' if ( $countryCode eq 'UK' );
        } else {
            $countryCode = $Common::Consts::COUNTRY_CODE{ lc $line->[ $offsets->{country} ] };
        }

        unless ($countryCode) {
            $self->errstr( "unknown country line $linenum: " . $line->[ $offsets->{country} ] );
            return undef;
        }

        my $month = $line->[ $offsets->{month} ];
        if ( ( length($month) == 1 ) && ( $month < 10 ) ) {
            $month = "0" . $month;
        } elsif ( $month !~ /^\d{1,2}$/ )    # month must be 1 or 2 digits
        {
            $self->errstr("Invalid month '$month' in line $linenum");
            return undef;
        }

        my $year = $line->[ $offsets->{year} ];
        if ( $year !~ /^\d{4}$/ ) {
            $self->errstr("Invalid year '$year' in line $linenum");
            return undef;
        }

        my $date = $year . "-" . $month . "-01";

        my ( $dateBegin, $dateEnd ) = $self->_getDates( date_begin => $date );

        unless ( defined $dateBegin && defined $dateEnd ) {
            $self->errstr( "couldn't get dates from " . $line->[ $offsets->{date} ] );
            return undef;
        }

        my $sales   = round( $line->[ $offsets->{sales} ] );
        my $returns = round( $line->[ $offsets->{returns} ] );
        $returns *= -1 if ( $returns < 0 && $self->{clientID} != 27 );

        #$returns            *= -1;

        # JPK
        # Localization.
        # net_usd is really 'net_base_currency'.
        # Won't we need to be prepared to localize this regex?
        #
        # No - In theory all of the numeric values will always be in 'us'
        # format : 12345.67
        #
        my $price        = $line->[ $offsets->{price} ];
        my $wholesale    = $line->[ $offsets->{wholesale_price} ];
        my $retailPrice  = $line->[ $offsets->{retail_price} ];
        my $salesPrice   = $line->[ $offsets->{sales_price} ];
        my $returnsPrice = $line->[ $offsets->{returns_price} ];
        my $netPrice     = $line->[ $offsets->{net_price} ];
        my $netUnits     = $line->[ $offsets->{net_units} ];
        my $grossRevenue = 0;
        if ( $offsets->{gross_revenue} ) {
            $grossRevenue = $line->[ $offsets->{gross_revenue} ];
        }
        $sales   = 0 if ( $sales eq "" );
        $returns = 0 if ( $returns eq "" );

        if ( $self->_version == 6 ) {
            $sales =        abs $netUnits if $netPrice >= 0;
            $returns =      abs $netUnits if $netPrice < 0;
            $salesPrice =   $netPrice if $netPrice >= 0;
            $returnsPrice = $netPrice if $netPrice < 0;
        }

        $returnsPrice *= -1 if ( $returnsPrice < 0 && $self->{clientID} != 27 );
        $returns *= -1 if ( $self->{clientID} == 27 );

        if ( sprintf( "%.2f", ( $salesPrice - $returnsPrice ) ) != sprintf( "%.2f", $netPrice ) ) {
            print STDERR "Mismatched SalesRevenue/ReturnsRevenue at line:" . $linenum . "\n";
            $self->errstr( "Mismatched SalesRevenue/ReturnsRevenue at line:" . $linenum );
            return undef;
        }

        if ( $sales - $returns ne $line->[ $offsets->{net_units} ] ) {
            print STDERR "Mismatched Sale/Returns at line:" . $linenum . "\n";
            $self->errstr( "Mismatched Sale/Returns at line:" . $linenum );
            return undef;
        }

        # JPK - This will need to get a little fancier.
        #
        my $convRate = 1;
        $convRate = 0 if ( $currencyCode ne Common::Client::Current()->Locale()->currencyFormat()->currencyCode() );

        my $skipSale = 0;
        if ( $label =~ /datapak/i && $self->{clientID} == 27 ) {
            $skipSale = $self->_filterDatapakSale( $catno, $upc );
            if ( $skipSale > 2 ) {
                $catno    = $skipSale;
                $skipSale = 0;
            }
            $catno =~ s/\s.*$//;
        }

        # If the 'free goods' flag is set, I don't believe we need to concern ourselves with any pricing.
        #
        my $free = uc( $line->[ $offsets->{free} ] ) eq 'Y' ? 1 : 0;
        if ($free) {
            $netPrice = $salesPrice = $returnsPrice = 0;
        }

        my $adjustment = uc( $line->[ $offsets->{adjustment} ] ) eq 'Y' ? 1 : 0;
        my $comments;
        if ($adjustment) {

            # !!! Only sale units should be specified for an adjustment.
            #
            $comments = $line->[ $offsets->{comments} ];

            unless ( $netUnits == 0 ) {
                $self->errstr("units must be set to 0 for adjustments - line $linenum");
                return undef;
            }

        }

        # Parse the 'Royalty Type' column, if any.
        #

        my $usMechStatus = 0;
        my $caMechStatus = 0;
        my $ukMechStatus = 0;
        my $labelStatus  = 0;
        my $artistStatus = 0;

        if ( defined $offsets->{royalty_type} ) {
            #
            my $royaltyType = uc( $line->[ $offsets->{royalty_type} ] );
            if ( $royaltyType && 'ALL' ne $royaltyType ) {

                # Turn -off- all the types, and only enable those that were specified.
                #
                $usMechStatus = 2;
                $caMechStatus = 2;
                $ukMechStatus = 2;
                $labelStatus  = 2;
                $artistStatus = 2;

                my @types = split( ' ', $royaltyType );
                foreach my $type (@types) {
                    my $testType = uc($type);
                    if ( 'ARTIST' eq $testType ) {
                        $artistStatus = 0;
                    } elsif ( 'LABEL' eq $testType ) {
                        $labelStatus = 0;
                    } elsif ( 'US-MECH' eq $testType ) {
                        $usMechStatus = 0;
                    } elsif ( 'CA-MECH' eq $testType ) {
                        $caMechStatus = 0;
                    } elsif ( ( 'UK-MECH' eq $testType ) || ( 'GB-MECH' eq $testType ) ) {
                        $ukMechStatus = 0;
                    } else {
                        $self->errstr( "invalid royalty type (" . $line->[ $offsets->{royalty_type} ] . "): line $linenum" );
                        return undef;
                    }
                }
            }
        }

        if (   $productType
            && ( $retailPrice || $free || $netPrice != 0 || $salesPrice != 0 || $returnsPrice != 0 || $sales != 0 || $returns != 0 )
            && ( $album || $upc || $catno )
            && $skipSale == 0 ) {
            my $sale = RPS::Import::SaleRec->new();

            $sale->serviceID($serviceID);
            $sale->productType($productType);
            $sale->dateBegin($dateBegin);
            $sale->dateEnd($dateEnd);
            $sale->labelName($label);
            $sale->outlet($label);
            $sale->clientProductID($catno);
            $sale->artistName($artist);
            $sale->albumName($album);
            $sale->upc($upc);
            $sale->free($free);
            $sale->price($price);
            $sale->wholesalePrice($wholesale);
            $sale->retailPrice($retailPrice);
            $sale->sales($sales);
            $sale->salesRevenue($salesPrice);
            $sale->returns($returns);
            $sale->returnsRevenue($returnsPrice);
            $sale->totalRevenue($netPrice);
            $sale->priceLevel($priceLevel);
            $sale->channel($channel);
            $sale->configuration($config);
            $sale->countryCode($countryCode);
            $sale->currencyCode($currencyCode);
            $sale->conversionRate($convRate);
            $sale->lineNum($linenum);
            $sale->mcps_adjustment($adjustment);
            $sale->comments($comments);
            $sale->mechanical_royalty_status($usMechStatus);
            $sale->ca_mechanical_royalty_status($caMechStatus);
            $sale->uk_mechanical_royalty_status($ukMechStatus);
            $sale->artist_royalty_status($artistStatus);
            $sale->label_royalty_status($labelStatus);
            $sale->grossRevenue($grossRevenue);

            $self->_insertSale( sale => $sale );
        } elsif ( $productType && $netPrice ne "" && ( $album || $upc || $catno ) && $skipSale == 1 ) {
            my @datapakCollectionCatalog = ( 1088, 1099, 1152, 1170, 1236, 9034 );

            $salesPrice   /= @datapakCollectionCatalog;
            $returnsPrice /= @datapakCollectionCatalog;
            $netPrice     /= @datapakCollectionCatalog;
            for ( my $x = 0 ; $x < @datapakCollectionCatalog ; $x++ ) {
                print STDERR "Split 6 Remap 1228 -> " . $datapakCollectionCatalog[$x] . "\n";
                my $sale = RPS::Import::SaleRec->new();

                $sale->serviceID($serviceID);
                $sale->productType($productType);
                $sale->dateBegin($dateBegin);
                $sale->dateEnd($dateEnd);
                $sale->labelName($label);
                $sale->outlet($label);
                $sale->clientProductID( $datapakCollectionCatalog[$x] );
                $sale->artistName($artist);
                $sale->albumName($album);
                $sale->upc($upc);
                $sale->sales($sales);
                $sale->salesRevenue($salesPrice);
                $sale->returns($returns);
                $sale->returnsRevenue($returnsPrice);
                $sale->totalRevenue($netPrice);
                $sale->priceLevel($priceLevel);
                $sale->channel($channel);
                $sale->configuration($config);
                $sale->countryCode($countryCode);
                $sale->currencyCode($currencyCode);
                $sale->conversionRate($convRate);
                $sale->lineNum($linenum);
                $sale->grossRevenue($grossRevenue);

                $self->_insertSale( sale => $sale );
            }
        }
        $totalRevenue += $netPrice;
        $totalUnits   += $netUnits;

        $linenum++;
    }

    $totalRevenue = sprintf( "%.2f", $totalRevenue );

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

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

    $fileObj->Physical(1);
    $fileObj->Save();
    return $linenum;
}

sub _readHeader {
    my $self = shift;
    my $line = shift || return;

    my $serviceID     = $self->getServiceID( $line->[1] ) || $RPS::Import::ServiceMap::SERVICE_ALIASES{ lc $line->[1] };
    my $headerUnits   = $line->[3];
    my $headerRevenue = $line->[5];
    my $currencyCode  = $line->[7];

    return ( $serviceID, $headerUnits, $headerRevenue, $currencyCode );
}

sub _filterDatapakSale {
    my $self        = shift;
    my $catalog     = shift;
    my $upc         = shift;
    my @datapakSkip = (
        1151, 1152, 1215, 1161, 1173, 1174, 1209, 1210, 1183, 1184, 1232, 1233, 1238, 1240, 1247, 1248,
        1235, 1267, 1269, 1272, 1274, 1278, 1280, 1281, 1283, 1300, 1302, 1328, 9149, 1316, 1317, 1319,
        1320, 1307, 1308, 1245, 1246, 1275, 1277, 1295, 1296, 1298, 1299, 1303, 1305, 1031, 1035
    );

    my %datapakMap = (
        1026 => 1031,
        1150 => 1152,
        1154 => 1215,
        1172 => 1174,
        1208 => 1210,
        1212 => 1212,
        1231 => 1233,
        1239 => 1240,
        1249 => 1247,
        1234 => 1267,
        1268 => 1269,
        1273 => 1274,
        1279 => 1280,
        1282 => 1283,
        1301 => 1302,
        1327 => 1328,
        1315 => 1317,
        1318 => 1320,
        1306 => 1308,
        1244 => 1246,
        1276 => 1277,
        1294 => 1296,
        1297 => 1299,
        1304 => 1305,
    );
    $catalog =~ s/\s.*$//;
    $upc =~ s/\s.*//;
    for ( my $x = 0 ; $x < @datapakSkip ; $x++ ) {
        return 2 if ( $catalog == $datapakSkip[$x] );
    }
    if ( defined $datapakMap{$catalog} ) {
        print STDERR "FOUND REMAP c:" . $catalog . " t:" . $datapakMap{$catalog} . "\n";
        return $datapakMap{$catalog};
    } elsif ( $catalog == 1228 ) {
        return 1;
    } else {
        return 0;
    }

}

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