#!/usr/bin/perl

use strict;
use Getopt::Std;
use Data::Dumper;

use lib '/app/tools/common/lib';
use Common::RSApp;
use Common::RSMath;

use lib '/app/tools/rps/lib';
use RPS::DB::Item::ArtistContractTermReserve;
use RPS::DB::Item::ArtistRoyaltyIncomeItem;
use RPS::DB::Item::ArtistRoyaltyRun;
use RPS::DB::Item::ContractRateType;
use RPS::DB::Item::NewArtistContract;
use RPS::DB::Item::NewArtistContractTerm;
use RPS::DB::Item::Product;
use RPS::DB::Item::Track;

# Allow tuning of the verbosity of our output.
#
my $gVerbosityLevel = 1;

# Parse the command-line.
#
my %options;
parseCommandLine(\%options);

createArtistReservePipelineReport($options{clientID}, $options{runID});

#
# --- Subroutines
#

sub createArtistReservePipelineReport
{
    my ($clientID, $runID) = @_;

    # Instantiate the application singleton object.
    #
    my $appSingleton = Common::RSApp->new(clientID => $clientID);

    my %gPipeline;
    
    my $run = RPS::DB::Item::ArtistRoyaltyRun->Lookup(artist_royalty_run_id => $runID);
    my $runStatus = $run->status(); 
    my $payorID = $run->payor_id;

    _report("---checking for reserves in run: id = ".$runID);
    
    _report("---run status = ".$runStatus);

    _report("---payor id = ".$payorID);    

    # Let's grab all of the reserves from the current run first
    #
    my $currentReserves = RPS::DB::Item::ArtistContractTermReserve->GetByArtistRoyaltyRunID($runID);
    my $currentTaken = 1;

    while (my $runReserveItem = $currentReserves->next())
    {
        addReservesToHash($runReserveItem, $currentTaken, $runStatus, \%gPipeline);

    }
    
    if ($runStatus == 2)
    {
        # Now let's grab all of the reserves liquidated in the current run.
        # This will only work if the run has been committed.
        my $currentLiquidatedReserves = RPS::DB::Item::ArtistContractTermReserve->GetLiquidatedByArtistRoyaltyRunID($runID);
        $currentTaken = 0;
    
        while (my $runReserveItem = $currentLiquidatedReserves->next())
        {
            addReservesToHash($runReserveItem, $currentTaken, $runStatus, \%gPipeline);

        } 
    }   


    # Now we'll grab all of the reserves from the committed runs.
    # We're are also going to pass in the current run id, so that we can run this report
    # even if the current run has been committed.  
    # However, if subsequent runs have been completed/committed, this report will not be accurate.
    # 
    my $committedReserves = RPS::DB::Item::ArtistContractTermReserve->GetAllCommittedByPayorID($payorID, $runID);
    $currentTaken = 0;

    while (my $runReserveItem = $committedReserves->next())
    {
        addReservesToHash($runReserveItem, $currentTaken, $runStatus, \%gPipeline);

    }

    # Write the data out to the table
    #

    foreach my $regionID (keys %gPipeline)
    {

        #_report("---processing reserves for region id = ".$regionID);
        my $artistPayeeIDHash = $gPipeline{$regionID};

        foreach my $artistPayeeID (keys %$artistPayeeIDHash)
        {

            #_report("---processing artist payee id = ".$artistPayeeID);
            my $albumIDHash = $artistPayeeIDHash->{$artistPayeeID};

            foreach my $albumID (keys %$albumIDHash)
            {
                my $data = $albumIDHash->{$albumID};

                #_report("---processing album id = ".$albumID);
                #_report("-----total revenue = ".$data->{totalRevenue});
                #_report("-----total units = ".$data->{totalUnits});

                my $insertSQL = "INSERT INTO artist_reserve_pipeline SET "
                  . 'artist_royalty_run_id=?,'
                  . 'artist_payee_id=?,'
                  . 'album_id=?,'
                  . 'region_id=?,'
                  . 'total_revenue=?,'
                  . 'total_units=?,'
                  . 'revenue_0=?,'
                  . 'units_0=?,'
                  . 'revenue_1=?,'
                  . 'units_1=?,'
                  . 'revenue_2=?,'
                  . 'units_2=?,'
                  . 'revenue_3=?,'
                  . 'units_3=?,'
                  . 'revenue_4=?,'
                  . 'units_4=?,'
                  . 'revenue_5=?,'
                  . 'units_5=?,'
                  . 'revenue_6=?,'
                  . 'units_6=?,'
                  . 'revenue_7=?,'
                  . 'units_7=?,'
                  . 'revenue_8=?,'
                  . 'units_8=?,'                  
                  . 'revenue_9=?,'
                  . 'units_9=?';

                my $dbo = Common::RSApp::GetClientDB();
                $dbo->DoCmdWithPlaceholders($insertSQL,
                    [
                        $runID,
                        $artistPayeeID,
                        $albumID,
                        $regionID,
                        $data->{totalRevenue},
                        $data->{totalUnits},
                        $data->{0}{revenue},
                        $data->{0}{units},
                        $data->{1}{revenue},
                        $data->{1}{units},
                        $data->{2}{revenue},
                        $data->{2}{units},
                        $data->{3}{revenue},
                        $data->{3}{units},
                        $data->{4}{revenue},
                        $data->{4}{units},
                        $data->{5}{revenue},
                        $data->{5}{units},
                        $data->{6}{revenue},
                        $data->{6}{units},
                        $data->{7}{revenue},
                        $data->{7}{units},
                        $data->{8}{revenue},
                        $data->{8}{units},
                        $data->{9}{revenue},
                        $data->{9}{units}                        
                    ]
                  );
            }
        }
    }
}

sub addReservesToHash
{
    my ($runReserveItem, $currentTaken, $runStatus, $pipeline) = @_;

    my $reserveID = $runReserveItem->artist_contract_term_reserve_id;

    my $reserve = RPS::DB::Item::ArtistContractTermReserve->Lookup(artist_contract_term_reserve_id => $reserveID);
    my $productID = $reserve->product_id;
    my $regionID = $reserve->region_id;

    my $product = RPS::DB::Item::Product->Lookup(product_id => $productID);
    my $albumID = _getAlbumIDFromProduct($product);

    my $termID = $reserve->artist_contract_term_id;
    my $term = RPS::DB::Item::NewArtistContractTerm->Lookup(artist_contract_term_id => $termID);
    my $artistContractID = $term->artist_contract_id;
    my $artistContract = RPS::DB::Item::NewArtistContract->Lookup(artist_contract_id => $artistContractID);
    my $artistPayeeID = $artistContract->artist_payee_id;

    my $reservePeriod = $reserve->periods_remaining; 

    my $reserveRevenue = $reserve->revenue;
    my $reserveUnits = $reserve->units;
    my $liquidated = $reserve->liquidated_run_id;
    
    if ($runStatus != 2 && $reservePeriod == 1)
    {
        $liquidated = 1;
    }

    if ($runStatus == 2)
    {    
        # I'm going to increment this by one to make room for the current 
        # liquidations if we are dealing with a committed run.
        #         
        $reservePeriod++;
    }
    
    my $effectiveRate = _calculateEffectiveRate($reserve, $term, $artistContract);

    my $incomeItemID = $reserve->original_statement_item_id;
    my $incomeItem = RPS::DB::Item::ArtistRoyaltyIncomeItem->Lookup(artist_royalty_income_item_id => $incomeItemID);
    my $units;
    my $grossSales;
    my $revenueReserved;
    my $reserveRate;
    my $totalUnitsReserved;
    my $liquidationPercentage;
    my $liquidationUnits;

    if ($incomeItem)
    {
        $units = $incomeItem->net_units;
        $grossSales = $incomeItem->revenue;
        $revenueReserved = $incomeItem->revenue_reserved;
        if ($revenueReserved != 0 && $grossSales != 0)
        {
            $reserveRate = $revenueReserved / $grossSales;
            $totalUnitsReserved = Common::RSMath::round($units * $reserveRate);

            $liquidationPercentage = $reserveRevenue / $revenueReserved;
            $liquidationUnits = $totalUnitsReserved * $liquidationPercentage;

        }
    }


    if (! $liquidated)
    {

        if ($reserve->revenue_based)
        {
            if ($incomeItem)
            {
                $pipeline->{$regionID}{$artistPayeeID}{$albumID}{totalUnits} += $liquidationUnits;
            }
            $pipeline->{$regionID}{$artistPayeeID}{$albumID}{totalRevenue} += $reserveRevenue;
    
        }
        else
        {
            $pipeline->{$regionID}{$artistPayeeID}{$albumID}{totalUnits} += $reserveUnits;
            $pipeline->{$regionID}{$artistPayeeID}{$albumID}{totalRevenue} += ($reserveUnits * $effectiveRate);
        }
    }
    else
    {
        #_report("-------found liquidations for this run: reserve id = $reserveID");
        # If these reserves are being liquidated, we'll set the reserve period to 1 
        # so that they show up in the proper place in the hash.
        #
        $reservePeriod = 1;   
    }    


    if ($reserve->revenue_based)
    {

#_report("-------reserve period = ".$reservePeriod." -- revenue = ".$reserveRevenue);
        $pipeline->{$regionID}{$artistPayeeID}{$albumID}{$reservePeriod}{revenue} += $reserveRevenue;

        if ($incomeItem)
        {
            $pipeline->{$regionID}{$artistPayeeID}{$albumID}{$reservePeriod}{units} += $liquidationUnits;
        }

    }
    else
    {

#_report("-------reserve period = ".$reservePeriod." -- units = ".$reserveUnits);
        $pipeline->{$regionID}{$artistPayeeID}{$albumID}{$reservePeriod}{units} += $reserveUnits;
        $pipeline->{$regionID}{$artistPayeeID}{$albumID}{$reservePeriod}{revenue} += ($reserveUnits * $effectiveRate);

    }

    # We want to display a total for reserves taken in the current period.
    #
    if ($currentTaken == 1)
    {
        if ($reserve->revenue_based)
        {

#_report("-------current period = ".$reservePeriod." -- revenue = ".$reserveRevenue);
            $pipeline->{$regionID}{$artistPayeeID}{$albumID}{0}{revenue} += $reserveRevenue;

            if ($incomeItem)
            {
                $pipeline->{$regionID}{$artistPayeeID}{$albumID}{0}{units} += $liquidationUnits;
            }
        }
        else
        {

#_report("-------current period = ".$reservePeriod." -- units = ".$reserveUnits);
            $pipeline->{$regionID}{$artistPayeeID}{$albumID}{0}{units} += $reserveUnits;
            $pipeline->{$regionID}{$artistPayeeID}{$albumID}{0}{revenue} += ($reserveUnits * $effectiveRate);

        }
    }

}

sub _calculateEffectiveRate
{
    my ($reserve, $term, $contract) = @_;

    my $effectiveRate;

    my $baseRate = $reserve->effective_rate;
    my $price = $reserve->price;
    my $rateReduction = $term->rate_reduction;
    my $percentageOfSales = $term->percentage_of_sales;
    my $packagingDeduction = $term->packaging_deduction;
    my $freeGoods = $term->free_goods_deduction;

#if ($reserve->revenue_based)
#{
#
#    $effectiveRate = $baseRate;
#    $effectiveRate = ($effectiveRate * ($percentageOfSales / 100)) if $percentageOfSales;
#    $effectiveRate = ($effectiveRate * ($rateReduction / 100)) if $rateReduction;
#    $effectiveRate = ($effectiveRate * ((100 - $packagingDeduction) / 100)) if $packagingDeduction;
#
#}
#else
#{

    $effectiveRate = $price;
    my $rateType = $term->contract_rate_type_id;
    if (RPS::DB::Item::ContractRateType::kRateTypeFixed == $rateType)
    {
        $effectiveRate = ($effectiveRate * $baseRate);
    }
    else
    {
        $effectiveRate = ($effectiveRate * ($baseRate / 100));
    }
    $effectiveRate = ($effectiveRate * ($rateReduction / 100)) if $rateReduction;
    $effectiveRate = ($effectiveRate * ((100 - $packagingDeduction) / 100)) if $packagingDeduction;

    #}

    return $effectiveRate;

}

sub _getAlbumIDFromProduct
{
    my ($product) = @_;

    if (RPS::DB::Item::Product::kProductTypeDigitalTrack == $product->product_type_id)
    {
        my $trackID = $product->asset_id;
        my $track = RPS::DB::Item::Track->Lookup(track_id => $trackID);
        return $track->album_id;
    }
    else
    {
        return $product->asset_id;
    }
}

#
# Boring script stuff below...
#

sub parseCommandLine
{
    my ($settings) = @_;

    my %opt;
    getopts('c:r:', \%opt);

    if (! $opt{c} || ! $opt{r})
    {
        usage();
        exit(1);
    }
    $settings->{clientID} = $opt{c};
    $settings->{runID} = $opt{r};

}

sub usage
{
    print STDERR "\nusage: $0 -c <client_id> -r <run_id>\n";
    print STDERR "\n";
    print STDERR "Arguments:\n";
    print STDERR "\t-c <client_id>\t\t\tThe client_id of the client to process\n";
    print STDERR "\t-r <run_id>\tThe id of the artist royalty run to process\n";
}

sub _report
{
    my ($string, $verbosity) = @_;
    $verbosity = 1 unless defined $verbosity;

    if ($gVerbosityLevel >= $verbosity)
    {
        print STDERR $string . "\n";
    }
}

