use strict;
use lib '/app/tools/common/lib';
use lib '/app/tools/raptor/lib';
use lib '/app/tools/rps/lib';

use Common::RSApp;
use Common::Client;
use Common::Log;
use Raptor::DB::Item::Sale;
use Raptor::DB::Item::File;
use RPS::Sale::Match;
use RPS::File::Sale;

my $clientID = $ARGV[0];
my $app      = Common::RSApp->new( clientID => $clientID );
my $client   = Common::Client::Current();

Common::Log::Print( "running for client $clientID: " . $client->ClientName() );

# Step one:  Find bad sales.
my $badSales =
  Raptor::DB::Item::Sale->GetAll("SELECT * FROM sale WHERE product_id > 0 AND product_id NOT IN (select product_id from product)");
my $badCount = $badSales->size();
my $count    = 0;

my $matchCount = 0;
my $matcher = RPS::Sale::Match->new( client_id => $clientID );

my %badFileSale;

my $unitSum;
my $revenueSum;

while ( my $sale = $badSales->next() ) {
    $count++;
    if ( 0 == $count % 1000 ) {
        Common::Log::Print("$count / $badCount");
    }

    # Let's try and re-match this sale.
    #
    my $file          = Raptor::DB::Item::File->Lookup( file_id => $sale->file_id() );
    my $fileServiceID = $file->service_id();
    my $matchData     = {
        service_id         => $fileServiceID,
        media_type         => $sale->media_type(),
        album              => $sale->album_name(),
        artist             => $sale->artist_name(),
        client_product_id  => $sale->client_product_id(),
        format             => $sale->format_type(),
        isrc               => $sale->isrc(),
        product_type       => $sale->product_type(),
        service_product_id => $sale->service_product_id(),
        track_num          => $sale->track_num,
        track              => $sale->track_name,
        upc                => $sale->upc,
        outlet             => $sale->outlet,
    };

    my $result = $matcher->FindBestMatch( data => $matchData, min_match_level => 90, skip_rec => 1 );
    if ( File::Sale::STATUS_MATCH == $result->ImportStatus ) {
        my $matchingProductID = $result->ProductIDs->[0];
        Common::Log::Print( " sale " . $sale->sale_id . " MATCHES product $matchingProductID" );
        $matchCount++;

        my $units = $sale->units();
        if ( $sale->sales() > 0 || $sale->returns() > 0 ) {
            $units = $sale->sales() - $sale->returns();
        }
        my $revenue = $units * $sale->price();
        $unitSum    += $units;
        $revenueSum += $revenue;

        # Ok... Let's go ahead and re-assign these product ids.o
        #
        $sale->product_id($matchingProductID);
        $sale->save();
    } elsif ( File::Sale::STATUS_MAPPED == $result->ImportStatus
        || File::Sale::STATUS_AUTO_MAPPED == $result->ImportStatus ) {
        Common::Log::Print( "MAPPED SALE: ", $sale, " MATCH: ", $result );

        my $matchingProductID = $result->ProductIDs->[0];
        $sale->product_id($matchingProductID);
        $sale->map_id( $result->MapID );
        $sale->import_status( $result->ImportStatus() );
        $sale->save();
    } else {
        Common::Log::Print( " sale " . $sale->sale_id . " NO MATCH", $sale, $result );
        Common::Log::Print( "sale " . $sale->sale_id . ", file " . $sale->file_id . ", line " . $sale->line_num );

        push @{ $badFileSale{ $sale->file_id } }, $sale->sale_id;
    }
}

# Let's look again at the files we might need to 'split' - Let's see if we already have a split file in period 0.
#

foreach my $badFileID ( keys %badFileSale ) {
    my $badSales = $badFileSale{$badFileID};

    my $file = Raptor::DB::Item::File->Lookup( file_id => $badFileID );
    my $childFile;

    my $parentFileID = $badFileID;
    while ( my $f = Raptor::DB::Item::File->Lookup( parent_file_id => $parentFileID ) ) {
        $childFile    = $f;
        $parentFileID = $childFile->file_id;
    }

    Common::Log::Print( "FILE: $badFileID, period " . $file->period_id() . "  Sale count: " . scalar @$badSales );
    if ($childFile) {
        Common::Log::Print( "  LEAF CHILD: " . $childFile->file_id() . ", period " . $childFile->period_id() );
        $file = $childFile;
    }

    # !!! One thing that needs to be considered:  If a file only has one sale, or if all the sales in a file
    # !!! (that is in a closed period) are 'bad', then we don't need to split the file: We need to re-open it.
    #
    # So let's get a count of the number of sales first.
    #
    my $allOriginalSales  = Raptor::DB::Item::Sale->GetAll("SELECT * FROM sale WHERE file_id = $badFileID");
    my $originalSaleCount = $allOriginalSales->size();
    my $badSaleCount      = scalar(@$badSales);

    Common::Log::Print("original sale count: $originalSaleCount,  bad sale count: $badSaleCount");

    # BEFORE we split any files, we need to re-set these 'bad' sales to appear
    # unmatched.   Otherwise the Split code will not work correctly.
    #
    foreach my $badSaleID (@$badSales) {
        my $sale = Raptor::DB::Item::Sale->Lookup( sale_id => $badSaleID );
        $sale->product_id(undef);
        $sale->map_id(undef);
        $sale->import_status(File::Sale::STATUS_NOMATCH);
        $sale->save();

        Common::Log::Print("  re-set sale $badSaleID");
    }

    my $oldFileID = $file->file_id();
    my $newFileID;
    if ( $badSaleCount == $originalSaleCount ) {

        # All sales are bad.
        # We need to possibly re-open the file, but the file_id will not change.
        #
        if ( 0 != $file->period_id() ) {
            Common::Log::Print( "  re-opening file " . $file->file_id() );
            $file->period_id(0);
            $file->file_status(4);
            $file->save();

            $newFileID = $file->file_id();
        }
    } elsif ( 0 == $file->period_id ) {

        # Have a split file already, just move the sales.
        #
        Common::Log::Print( "  using existing child file " . $file->file_id() );
        $newFileID = $file->file_id();
    } else {

        # Need to split
        #
        Common::Log::Print("  Need to split file");
        my $oldFile = RPS::File::File->new( file_id => $file->file_id() );
        my $newFile = $oldFile->Split();
        $newFileID = $newFile->FileID();

        # The Split method clones the original file, which is _usually_ in period 0, and Open.
        # Meaning, it doesn't bother to actually _set_ these fields. Since we are splitting a closed
        # file in a different period, we need to set these fields explicitly.
        #
        $newFile->PeriodID(0);
        $newFile->FileStatus(4);
        $newFile->Save();
        Common::Log::Print("  new file id: $newFileID");
    }

    # This may be redundant if the file was actually split, but should be harmless.
    #
    foreach my $badSaleID (@$badSales) {
        my $sale = Raptor::DB::Item::Sale->Lookup( sale_id => $badSaleID );

        # This may be redundant with files that we just split, but it won't hurt.
        #
        $sale->file_id($newFileID);
        $sale->save();

        Common::Log::Print("  updated sale $badSaleID");
    }

    # Re-calculate summary data.
    #
    my $oldFile = RPS::File::File->new( file_id => $oldFileID );
    $oldFile->UpdateSummary( skip_conversion => 1 );
    $oldFile->RecalculateRemainingExceptions();

    if ( $oldFileID != $newFileID ) {
        my $newFile = RPS::File::File->new( file_id => $newFileID );
        $newFile->UpdateSummary( skip_conversion => 1 );
        $newFile->RecalculateRemainingExceptions();
    }
}

Common::Log::Print("UNIT SUM RECOVERED: $unitSum   REVENUE RECOVERED: $revenueSum");
