#!/usr/bin/perl
#------------------------------------------------------------ 
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#------------------------------------------------------------ 
use strict;

use Data::Dumper;
use Getopt::Std;
use POSIX qw(ceil);
use Carp;

use lib '/app/tools/common/lib';
use Common::Assert;

use lib '/app/tools/rps/lib';
use RPS::RoyaltyRun::Status;
use RPS::DB::Item::ArtistPayee;
use RPS::DB::Item::ArtistPayeeAccount;
use RPS::DB::Item::ArtistRoyaltyAlbum;
use RPS::DB::Item::ArtistRoyaltyAlbumBalanceAccount;
use RPS::DB::Item::ArtistRoyaltyExpenseItem;
use RPS::DB::Item::ArtistRoyaltyIncomeItem;
use RPS::DB::Item::ArtistRoyaltyRun;
use RPS::DB::Item::ArtistRoyaltyStatement;
use RPS::DB::Item::Expense;
use RPS::DB::Item::FinanceAccount;
use RPS::DB::Item::FinanceTransaction;
use RPS::DB::Item::SaleArtistRoyaltyRunMap;

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


my $gVerbosityLevel = 1;

# Get the id from the command-line
#
my %options;
_parseCommandLine(\%options);
_uncommitRun($options{clientID}, $options{runID});


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

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

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

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

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


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

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


    # Get the run state, and make sure it is committed.
    #
    my $run = RPS::DB::Item::ArtistRoyaltyRun->Lookup(artist_royalty_run_id => $runID);
    die "royalty run $runID does not exist!" unless $run;

    if (RPS::RoyaltyRun::Status::kCommitted != $run->status)
    {
        die "run $runID has not been committed";
    }

    _report("*** Rolling Back Artist Royalty Run $runID ***\n");

    
    # Fetch all the statements in this run
    #
    my $statements = RPS::DB::Item::ArtistRoyaltyStatement->GetByArtistRoyaltyRunID($runID);

    _report("statements to un-commit: " . $statements->size(), 2);
    while ($statements->hasNext())
    {
        my $statement = $statements->next();
        _uncommitStatement($statement);
    }


    # Reset the status of all sales processed in this run.
    #
    my $saleMapItems = RPS::DB::Item::SaleArtistRoyaltyRunMap->GetByArtistRoyaltyRunID($runID);
    if ($saleMapItems)
    {
        _report("marking " . $saleMapItems->size() . " sales as unprocessed", 2);
        while (my $saleMapItem = $saleMapItems->next())
        {
            my $sale = Raptor::DB::Item::Sale->Lookup(sale_id => $saleMapItem->sale_id);
            $sale->artist_royalty_status(Raptor::DB::Item::Sale::kUnprocessed);
            $sale->save();
        }
    }


    # Delete sale map entries
    #
    _report("deleting from sale map");
    RPS::DB::Item::SaleArtistRoyaltyRunMap->DeleteByArtistRoyaltyRunID($runID);


    # Deleting the run.
    #
    _report("deleting from artist royalty run table");
    $run->delete();
#    RPS::DB::Item::ArtistRoyaltyRun::DeleteArtistRoyaltyRun($runID);
}


sub _uncommitStatement
{
    my ($statement) = @_;

    my $statementID = $statement->artist_royalty_statement_id;
    my $payorID = $statement->payor_id;
    my $artistPayeeID = $statement->payee_id;

    _report("\n------------------------------------\n", 2);

    _report("un-committing statement id $statementID", 2);


    # Go through each album on the statement.
    #
    my $albums = RPS::DB::Item::ArtistRoyaltyAlbum::GetByArtistRoyaltyStatementID($statementID);
    while (my $album = $albums->next())
    {
        _uncommitAlbum($album, $statement);

        # Delete the income and expense items
        #
        my $albumID = $album->artist_royalty_album_id;

        _report("  ... deleting income items",2);
        RPS::DB::Item::ArtistRoyaltyIncomeItem->DeleteByArtistRoyaltyAlbumID($albumID);
        _report("  ... deleting expense items",2);
        RPS::DB::Item::ArtistRoyaltyExpenseItem->DeleteByArtistRoyaltyAlbumID($albumID);
    }


    # Delete all the album items
    #
    _report("  ... deleting artist royalty albums",2);
    RPS::DB::Item::ArtistRoyaltyAlbum->DeleteByArtistRoyaltyStatementID($statementID);


    # Now handle the holdover account
    # It's ok to leave the ArtistPayeeAccount record in place, and to leave the
    # account there.  But, we need to remove the transactions from the account that
    # are associated with this run.  This is the hard part...
    #
    # !!! I am going to have to use the memo field to pull this off.  Which is _not_ what it
    # !!! was intended for.  This is very fragile - changes to the way we write out the memo
    # !!! will break this.
    #
    # !!! And if the 'artist statement x' transaction is not the _last_ transaction posted to that 
    # !!! account, we're hosed.
    #
    my $payeeAccountMap = RPS::DB::Item::ArtistPayeeAccount->Lookup(artist_payee_id => $artistPayeeID, payor_id => $payorID);
    if ($payeeAccountMap)
    {
        my $payeeAccountID = $payeeAccountMap->finance_account_id;
        if ($payeeAccountID)
        {
            my $transaction = RPS::DB::Item::FinanceTransaction->Lookup
            (
            
                finance_account_id => $payeeAccountID,
                memo => "artist statement $statementID",
            );
            if ($transaction)
            {
                $transaction->delete();
            }
        }
    }


    # Now delete the statement stuff
    #
    $statement->delete();
}


sub _uncommitAlbum
{
    my ($album, $statement) = @_;

    
    my $payorID = $statement->payor_id;
    my $artistPayeeID = $statement->payee_id;
    my $albumID = $album->album_id;
    my $statementID = $statement->artist_royalty_statement_id;


    # Get the account, post the transaction
    #
    my $accountID;
    my $accountMap = RPS::DB::Item::ArtistRoyaltyAlbumBalanceAccount->Lookup
    (
        album_id => $albumID, 
        artist_payee_id => $artistPayeeID,
        payor_id => $payorID,
    );

    if ($accountMap)
    {
        $accountID = $accountMap->account_id;


        # Find the transaction to eliminate.
        #
        my $transaction = RPS::DB::Item::FinanceTransaction->Lookup
        (
            finance_account_id => $accountID,
            type_code => RPS::DB::Item::FinanceTransaction::kTypeAdjustment,
            memo => "artist statement $statementID",
        );
        if ($transaction)
        {
            $transaction->delete();
        }
    }



    # Reset the status of the expenses.

    my $expenseItems = RPS::DB::Item::ArtistRoyaltyExpenseItem->GetByArtistRoyaltyAlbumID($album->artist_royalty_album_id);
    if ($expenseItems)
    {
        _report("marking " . $expenseItems->size() . " expenses as 'unprocessed'", 2);
        while (my $expenseItem = $expenseItems->next())
        {
            my $expense = RPS::DB::Item::Expense->Lookup(expense_id => $expenseItem->expense_id);
            $expense->processed(0);
            $expense->save();
        }
    }

}



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

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


