#!/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::TextProgressBar;
use Common::Timer;
use Common::DB::Item::Service;

#use lib '/app/tools/data_classes/lib';
#use File::Sale;
use lib '/app/tools/raptor/lib';
#use Raptor::Sale::Sale;
use Raptor::DB::Item::Sale;
use Raptor::DB::Item::File;

use lib '/app/tools/rps/lib';
use RPS::DB::Item::ArtistPayeeAccount;
use RPS::DB::Item::ArtistRoyaltyAlbum;
use RPS::DB::Item::ArtistRoyaltyRun;
use RPS::DB::Item::ArtistRoyaltyStatement;
use RPS::DB::Item::FinanceAccount;
use RPS::DB::Item::FinanceTransaction;
use RPS::DB::Item::ArtistRoyaltyAlbumBalanceAccount;

my $gVerbosityLevel = 1;



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


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


sub _fixRun
{
    my ($runID) = @_;

    _report("\n---- Converting run $runID");

    my $statements = RPS::DB::Item::ArtistRoyaltyStatement::GetByArtistRoyaltyRunID($runID);
    while (my $statement = $statements->next())
    {
        _fixStatement($statement);
    }
}


sub _fixStatement
{
    my ($statement) = @_;
    _report("  statement: " . $statement->artist_royalty_statement_id, 2);


    my $artistPayeeID = $statement->payee_id;
    my $statementTotal = $statement->total;
    my $amountDue = $statement->amount_due;

    my $financeAccountID = _artistPayeeAccountID($artistPayeeID, $statement->payor_id);

#    my $expectedTransactionAmount = ($amountDue > 0 ? $amountDue : $statementTotal);
    my $expectedTransactionAmount = $statementTotal;

    
    # If the expected amount is 0, then there shouldn't be any transactions?
    # Or, there should just be 1 transaction that established the 'previous balance'.
    #
    if (0 == $expectedTransactionAmount)
    {
        # We might end up here if there was an amount due that paid off the entire previous balance.
        # In that case, we want to roll back that transaction, and force them to make that payment the
        # next time we run.
        #
        my $lastTransaction = RPS::DB::Item::FinanceTransaction::GetLastAccountTransaction($financeAccountID);
        my $lastTransactionAmount;
        if ($lastTransaction)
        {
            $lastTransactionAmount = $lastTransaction->amount;
        }

        my $expectedMemo = "artist statement " . $statement->artist_royalty_statement_id;
        if ($lastTransaction && $lastTransaction->memo eq $expectedMemo)
        {
            _report("   going to eliminate the last transaction");
            $lastTransaction->delete();
        }

    }
    else
    {
        # grab the last transaction.
        #
        if (! $financeAccountID)
        {
            # If there is no account, then probably we need to create one:  Let's see if there was an expected amount.
            #
            if (0 != $expectedTransactionAmount)
            {
                _report("artist $artistPayeeID will need whole new account, with an amount of $expectedTransactionAmount");
                my $newAccount = RPS::DB::Item::FinanceAccount->Create
                (
                    description => 'account for artist payee ' . $artistPayeeID,
                    type_code => 1,
                );
                $newAccount->save();

                $financeAccountID = $newAccount->finance_account_id;

                # Should already be an account map, just with no account id.
                #
                my $accountMap = RPS::DB::Item::ArtistPayeeAccount->Lookup
                (
                    artist_payee_id => $artistPayeeID, 
                    payor_id => $statement->payor_id,
                );
                if (! $accountMap)
                {
                    _report("!!!! No account map created!");
                }
                $accountMap->finance_account_id($financeAccountID);
                $accountMap->save();
            }
        }

        my $lastTransaction = RPS::DB::Item::FinanceTransaction::GetLastAccountTransaction($financeAccountID);
        my $lastTransactionAmount;
        if ($lastTransaction)
        {
            $lastTransactionAmount = $lastTransaction->amount;
        }

        # !!! sanity check - should be a 'artist statement X' transaction
        #
        my $expectedMemo = "artist statement " . $statement->artist_royalty_statement_id;
        if ($lastTransaction && $lastTransaction->memo ne $expectedMemo)
        {
            _report(" !!! for artist $artistPayeeID, last transaction does not appear to be correct! " . Dumper($lastTransaction));
            return;
        }

        # Ok, so now we can see whether all is well.
        #
        if ($lastTransactionAmount != $expectedTransactionAmount)
        {
            _report(" !!! artist $artistPayeeID, last transaction amount of $lastTransactionAmount != expected $expectedTransactionAmount");

            # So, this would usually mean that I need to delete the last transaction, and re-post 
            #
            $lastTransaction->delete() if $lastTransaction;
            my $newTransaction = RPS::DB::Item::FinanceTransaction->Create
            (
                finance_account_id => $financeAccountID,
                amount => $expectedTransactionAmount,
                memo => $expectedMemo,
                type_code => RPS::DB::Item::FinanceTransaction::kTypeAdjustment,
            );
            $newTransaction->save();
        }
    }
}


sub _artistPayeeAccountID
{
    my ($payeeID, $payorID) = @_;

    my $accountMap = RPS::DB::Item::ArtistPayeeAccount->Lookup
    (
        artist_payee_id => $payeeID,
        payor_id => $payorID,
    );
    return undef unless defined $accountMap;
    return $accountMap->finance_account_id;
}

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";
    }
}


# Pass dates in 'yyyy-mm-dd' format.
#
sub _parseCommandLine
{
    my ($settings) = @_;

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

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

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