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


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}];
        $p = "unknown" 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          = Common::Util::normalize_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}];
        $sales              = 0 if($sales eq "");
        $returns            = 0 if($returns eq "");
        $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);

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

                $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.
###
