#!/usr/bin/perl
use strict;


use Data::Dumper;
use Getopt::Std;
use POSIX qw(ceil);
use POSIX ":sys_wait_h";
use Sys::Hostname;
use Carp;


use lib '/app/tools/common/lib';
use Common::DB::Item;
use Common::Assert;
use Common::Client;
use Common::RSDB;


use lib '/app/tools/rps/lib';
use RPS::DB::Item::MechanicalRun;
use RPS::DB::Item::MechanicalStatement;
use RPS::DB::Item::MechanicalStatementItem;
use RPS::DB::Item::LicenseReserve;
use RPS::DB::Item::ReserveLiquidation;
use RPS::DB::Item::Product;

my $gVerbosityLevel = 1;


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

my $clientID = $options{clientID};

my $testing = $options{testing};
    
if ($testing)
{
_report("\n Test Mode Activated -- No reserves will be created!");       
}    
    
    
# Instantiate the application singleton object.
#
my $appSingleton = Common::RSApp->new(clientID => $clientID);

_report("\n Client $clientID");


_report("---- Checking US mechanicals");

my $runs = RPS::DB::Item::MechanicalRun->GetAll();
my @runIDs;

##  We created reserves differently in the past, so we will only be able to go back so far.
##
my $cutOffDate = "2008-06-30 01:01:01";

while (my $run = $runs->next())
{
    # We only care about committed or closed runs.
    # 
    if (($run->status == 2 || $run->status == 5) && $run->end_time ge $cutOffDate)
    {
        push(@runIDs, $run->mechanical_run_id); 
    }  
} 

my @statementIDs;

foreach my $runID (@runIDs)
{
    _report("-- checking run " . $runID);
    my $statements = RPS::DB::Item::MechanicalStatement->GetByMechanicalRunID($runID);
    
    while (my $statement = $statements->next())
    {
        push(@statementIDs, $statement->mechanical_statement_id);   
    }         
}

my $missingReserveGrandTotal = 0;
my $createdReserveGrandTotal = 0;

foreach my $statementID (@statementIDs)
{
    my $statementItems = RPS::DB::Item::MechanicalStatementItem->GetByMechanicalStatementID($statementID);
    
    while (my $statementItem = $statementItems->next())
    {       
        # First we'll see what's been reserved (if anything).
        #        
        my $statementItemReserved = $statementItem->reserved;
        
        if ($statementItemReserved > 0)
        {         
            my $trackLicenseID = $statementItem->track_license_id;
            my $statementItemID = $statementItem->mechanical_statement_item_id;
            
            # Now we need to check for an entry in the license_reserve table
            #
            my $reserveItems = RPS::DB::Item::LicenseReserve->GetByStatementItemID($statementItemID);
            my $reserveTotal = 0;
            while (my $reserveItem = $reserveItems->next())
            {            
                $reserveTotal += $reserveItem->units;
            }    
            
            # We need to play this really safe because of historical reserves,
            # so we're only going to create reserves if they are completely missing.
            # The original issue was reserves taken without a liquidation schedule,
            # so this should be okay.
            #if ($statementItemReserved != $reserveTotal)   
            
            if ($reserveTotal == 0)
            {
                _report("---- statementItemID $statementItemID: " . $statementItemReserved . " reserves");
                _report("---- license_reserve table: " . $reserveTotal . " reserves"); 
                _report("---- $statementItemReserved != $reserveTotal");     
                
                
                if ($statementItemReserved < $reserveTotal)
                {
                    # I don't think this will happen, but I want to know if it does.
                    die "ERROR - we have more reserves saved than we took... this is pretty messed up\n";
                }
                else
                {                         
                    my $missingReserves = $statementItemReserved - $reserveTotal;
                    $missingReserveGrandTotal += $missingReserves;
    
                    # Okay, let's do this.
                    #
                    my %scheduleTable;
                    my $schedule = RPS::DB::Item::ReserveLiquidation->GetByIDType($trackLicenseID, 1);
                    while (my $scheduleEntry = $schedule->next())
                    {
                        $scheduleTable{$scheduleEntry->period()} = $scheduleEntry->percent;
                    }
                    
                    my $createdReserve = 0;

                    my $initialUnits = $missingReserves;
                    for (my $i = 1; $missingReserves > 0 && $i <= 8; $i++)
                    {
                        my $p = $scheduleTable{$i};
                        next unless $p;
                
                        my $periodUnits = ceil($initialUnits * ($p / 100));
                        $periodUnits = $missingReserves unless $periodUnits < $missingReserves;
                
                        $missingReserves -= $periodUnits;
                        
                        #my $periodsRemaining = $i + 1;
                        my $periodsRemaining = $i;
                        
                        if (! $testing)
                        {
                            my $newReserve = _createLicenseReserve($statementItem, $periodUnits, $periodsRemaining);
                            $newReserve->save();
                        }
                        
                        $createdReserve = 1;
                        $createdReserveGrandTotal += $periodUnits;
                        _report("---- created reserve with $periodUnits units and $periodsRemaining periods remaining"); 
                
                    }
                    
                    # If for some reason we didn't create a reserve (like say the liquidation schedule is blank),
                    # that's bad news so we need to bail.
                    #
                    if ($createdReserve == 0)
                    {
                        die "ERROR - reserve was not created successfully for statement item: " . Dumper($statementItem) . "\n";
                    }                 
                }                
            } 
        }     
    }                        
}

_report("---- Missing reserve grand total is $missingReserveGrandTotal");  
_report("---- Created reserve grand total is $createdReserveGrandTotal"); 


sub _createLicenseReserve
{
    my ($statementItem, $units, $periodsRemaining) = @_;

    my $newReserve = RPS::DB::Item::LicenseReserve->Create
    (
        track_license_id => $statementItem->track_license_id,
        original_statement_item_id => $statementItem->mechanical_statement_item_id,
        product_id => $statementItem->product_id,
        sale_stat_rate_id => $statementItem->sale_stat_rate_id,
        issue_stat_rate_id => $statementItem->issue_stat_rate_id,
        units => $units,
        effective_rate => $statementItem->net_rate,
        periods_remaining => $periodsRemaining,
    );
    return $newReserve;
}



sub _usage
{
    print "\nusage: $0 -c client_id [-V]\n";
    print "\n";
    print "Arguments:\n";
    print "\t-c <client_id>\t\tThe client_id of the client to process\n";
    print "\t-V <N>\t\t\tVerbosity level - 0 means no output\n";
}


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

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


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

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

    $settings->{clientID} = $opt{c} if $opt{c};
    $settings->{testing} = 1 if $opt{t};

    if (defined $opt{V})
    {
        $gVerbosityLevel = $opt{V};
    }
}