#!/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::Util;


use lib '/app/tools/rps/lib';
use RPS::DB::Item::FinanceAccount;
use RPS::DB::Item::PublisherAccount;
use RPS::DB::Item::FinanceTransaction;
use RPS::DB::Item::ArtistPayeeAccount;
use RPS::DB::Item::ArtistPayee;


my $gVerbosityLevel = 1;

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


my @clientIDs;
if ($options{clientID})
{
    push @clientIDs, $options{clientID};
}
else
{

#    @clientIDs = _getAllAvailableClientIDs();
}


foreach my $clientID (@clientIDs)
{
    my $appSingleton = Common::RSApp->new(clientID => $clientID);

    _createAlert();
    _alterFinanceTransaction();
    _dropAlbumContractAdvance();
    _dropTrackContractAdvance();
    _createArtistPayeeAccount();
    _alterArtistPayee();
    _alterTrackLicense();
    _alterPublisher();
    _alterArtistRoyaltyAlbumBalanceAccount();
}

sub _alterFinanceTransaction
{
    _report("adding transaction_date to finance_transaction table");

    my $dbo = Common::RSApp::GetClientDB();
    $dbo->DoCmd("alter table finance_transaction add column `transaction_date` date default NULL");

}

sub _alterArtistRoyaltyAlbumBalanceAccount
{
    _report("adding payor_id to artist_royalty_album_balance_account");

    my $dbo = Common::RSApp::GetClientDB();
    $dbo->DoCmd("alter table artist_royalty_album_balance_account add column `payor_id` int(10) unsigned NOT NULL default '0'");
    $dbo->DoCmd("alter table artist_royalty_album_balance_account add key `payor_id` (`payor_id`)");

    $dbo->DoCmd("update artist_royalty_album_balance_account set payor_id=1");
}

sub _dropAlbumContractAdvance
{
    _report("dropping album_contract_advance table");
 	my $dbo = Common::RSApp::GetClientDB();
    $dbo->DoCmd('drop table album_contract_advance');
}

sub _dropTrackContractAdvance
{
    _report("dropping track_contract_advance table");
 	my $dbo = Common::RSApp::GetClientDB();
    $dbo->DoCmd('drop table track_contract_advance');
}


sub _createAlert
{
my $sql = "CREATE TABLE `alert` ("
    . "`alert_id` int(10) unsigned NOT NULL auto_increment,"
    . "`message` text,"
    . "`alert_level` tinyint(3) unsigned NOT NULL default '1',"
    . "`date_created` timestamp NOT NULL default '0000-00-00 00:00:00',"
    . "`created_by` int(10) unsigned NOT NULL default '0',"
    . "`date_modified` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,"
    . "`modified_by` int(10) unsigned NOT NULL default '0',"
    . "PRIMARY KEY  (`alert_id`))";

    _report("creating alert table");
 	my $dbo = Common::RSApp::GetClientDB();
    $dbo->DoCmd($sql);
}


sub _createArtistPayeeAccount
{
    # First, create the table.
    #
my $sql = "CREATE TABLE `artist_payee_account` ("
        . "`artist_payee_id` int(10) unsigned NOT NULL default '0',"
        . "`payor_id` int(10) unsigned NOT NULL default '0',"
        . "`finance_account_id` int(10) unsigned NOT NULL default '0',"
        . "`min_payment` decimal(16,4) NOT NULL default '0.0000',"
        . "`date_created` timestamp NOT NULL default '0000-00-00 00:00:00',"
        . "`created_by` int(10) unsigned NOT NULL default '0',"
        . "`date_modified` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,"
        . "`modified_by` int(10) unsigned NOT NULL default '0',"
        . "KEY `artist_payee_id` (`artist_payee_id`),"
        . "KEY `payor_id` (`payor_id`))";

    _report("creating artist_payee_account table");
 	my $dbo = Common::RSApp::GetClientDB();
    $dbo->DoCmd($sql);
    

    # Now populate this table.
    #
    _report("populating artist_payee_account table");
    $sql = "SELECT artist_payee_id,finance_account_id,opening_balance from artist_payee";
    my $sth = $dbo->DoCmd($sql);
    while (my $hr = $sth->fetchrow_hashref)
    {
        # If this artist already has an account, we're good to go.
        #
        my $accountID = $hr->{finance_account_id};
        if (! $accountID)
        {
            # Do we wish to have an opening balance?
            #
            if ($hr->{opening_balance} > 0)
            {
                _report("... creating a new account for artist_payee " . $hr->{artist_payee_id}, 2);
                my $newAccount = RPS::DB::Item::FinanceAccount->Create
                (
                    description => 'account for artist payee ' . $hr->{artist_payee_id},
                    type_code => RPS::DB::Item::FinanceAccount::kAccountTypeAdvance,
                );
                $newAccount->save();
                $accountID = $newAccount->finance_account_id;

                _report("..... creating opening balance of " . $hr->{opening_balance}, 2);
                my $newTransaction = RPS::DB::Item::FinanceTransaction->Create
                (
                    finance_account_id => $accountID,
                    amount => $hr->{opening_balance},
                    type_code => RPS::DB::Item::FinanceTransaction::kTypeOpeningBalance,
                    memo => "opening balance",
                );
                $newTransaction->save();
            }
        }


        #  !!! Don't create a mapping if they don't have an account...
        #
        if ($accountID)
        {
            _report("... creating artist_payee_account entry for artist_payee " . $hr->{artist_payee_id}, 2);
            my %createHash = 
            (
                artist_payee_id => $hr->{artist_payee_id},
                finance_account_id => $hr->{finance_account_id},
                payor_id => 1,      # hard coded to the default
            );
            if ($hr->{min_payment})
            {
                $createHash{min_payment} = $hr->{min_payment};
            }
            my $newPayeeAccount = RPS::DB::Item::ArtistPayeeAccount->Create(%createHash);
            $newPayeeAccount->save();
        }
    }
}


sub _alterArtistPayee
{
    my $dbo = Common::RSApp::GetClientDB();
    $dbo->DoCmd("ALTER TABLE artist_payee drop column opening_balance");
    $dbo->DoCmd("ALTER TABLE artist_payee drop column finance_account_id");
    $dbo->DoCmd("ALTER TABLE artist_payee drop column min_payment");
}


sub _alterTrackLicense
{
    my $dbo = Common::RSApp::GetClientDB();

    # Make sure all the advance balances are represented in the transaction table someplace.
    #
    _report("making sure all track_licenses with advances have accounts...");
    my $sth = $dbo->DoCmd("select track_license_id,advance_account_id,advance_amount from track_license");
    while (my $hr = $sth->fetchrow_hashref())
    {
        # presuming non-negative initial advances.
        #
        if (! $hr->{advance_account_id} && $hr->{advance_amount} > 0)
        {
            # Create an advance account, set up the initial balance.
            #
            _report("... creating a new account for track_license" . $hr->{track_license_id}, 2);
            my $newAccount = RPS::DB::Item::FinanceAccount->Create
            (
                description => 'account for track_license' . $hr->{track_license_id},
                type_code => RPS::DB::Item::FinanceAccount::kAccountTypeAdvance,
            );
            $newAccount->save();
            my $accountID = $newAccount->finance_account_id;

            _report("..... creating opening balance of " . $hr->{advance_amount}, 2);
            my $newTransaction = RPS::DB::Item::FinanceTransaction->Create
            (
                finance_account_id => $accountID,
                amount => $hr->{advance_amount},
                type_code => RPS::DB::Item::FinanceTransaction::kTypeOpeningBalance,
                memo => "opening balance",
            );
            $newTransaction->save();
        }
    }

    _report("altering track_license table");
    $dbo->DoCmd("alter table track_license drop column advance_amount");
    $dbo->DoCmd("alter table track_license change column advance_account_id finance_account_id int(10) unsigned");
}


sub _alterPublisher
{
    my $dbo = Common::RSApp::GetClientDB();

    _report("altering publisher table");
    # Create the new publisher_account table.
    #
my $sql = "CREATE TABLE `publisher_account` ("
        . "`payor_id` int(10) unsigned NOT NULL default '0',"
        . "`publisher_id` int(10) unsigned NOT NULL default '0',"
        . "`finance_account_id` int(10) unsigned default NULL,"
        . "`min_payment` decimal(16,4) NOT NULL default '0.0000',"
        . "`date_created` timestamp NOT NULL default '0000-00-00 00:00:00',"
        . "`created_by` int(10) unsigned NOT NULL default '0',"
        . "`date_modified` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,"
        . "`modified_by` int(10) unsigned NOT NULL default '0',"
        . "KEY `publisher_id` (`publisher_id`),"
        . "KEY `payor_id` (`payor_id`))";
    $dbo->DoCmd($sql);



    # So...  the goal here is to combine the finance_account and the advance_account.
    # The 'advance_account_id' in Publisher is already deprecated, as far as I can tell.
    #
    my $sth = $dbo->DoCmd("select * from publisher");
    while (my $hr = $sth->fetchrow_hashref())
    {
        my $publisherID = $hr->{publisher_id};

        _report("  publisher $publisherID", 2);
        # First, is there a publisher_advance record for this guy?
        # If there is, then create a corresponding publisher_account record.
        #
        my $advanceID;
        my $sth2 = $dbo->DoCmd("select * from publisher_advance where publisher_id=$publisherID");
        my $hr2 = $sth2->fetchrow_hashref();

        my $advanceAccountID = $hr2->{advance_account_id};
        my $financeAccountID = $hr->{finance_account_id};
        my $minPayment = $hr->{min_payment};
        $minPayment = 0 unless $minPayment;

        # Do we have any reason to mess with the publisher_account table?
        #
        if ($advanceAccountID || $financeAccountID || $minPayment > 0)
        {
            # If they have a finance account, we'll just use that.
            # Otherwise, create a new one.
            #
            my $financeAccount;
            if (! $financeAccountID)
            {
                _report("    creating a new finance account", 2);
                $financeAccount = RPS::DB::Item::FinanceAccount->Create
                (
                    description => "account for publisher $publisherID payor 1",
                    type_code => RPS::DB::Item::FinanceAccount::kAccountTypeAdvance,
                );
                $financeAccount->save();
                $financeAccountID = $financeAccount->finance_account_id;
            }



            # Now, if they have a publisher_advance record, we'll post transactions
            # from that to the (possibly new) account.
            #
            if ($advanceAccountID)
            {
                _report("    moving transactions from advance account to finance account", 2);
                my $advanceTransactions = RPS::DB::Item::FinanceTransaction::GetAccountTransactions(finance_account_id => $advanceAccountID);
                while (my $advanceTransaction = $advanceTransactions->next())
                {
                    my $newTransaction = RPS::DB::Item::FinanceTransaction->Create(finance_account_id => $financeAccountID);

                    # Note that this old 'advance account' had the sign flipped...
                    #
                    $newTransaction->amount(-1 * $advanceTransaction->amount);
                    $newTransaction->memo($advanceTransaction->memo);
                    $newTransaction->save();
                }
            }


            # Now we can create the publisher_account record.
            #
            my $publisherAccount = RPS::DB::Item::PublisherAccount->Create
            (
                payor_id => 1,  # using default payor
                publisher_id => $publisherID,
                finance_account_id => $financeAccountID,
                min_payment => $minPayment,
            );
            $publisherAccount->save();
        }
    }
}

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

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 STDERR $string . "\n";
    }
}


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

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

    if ($opt{d})
    {
        $settings->{deleteFirst} = 1;
    }


    if ($opt{c})
    {
        $settings->{clientID} = $opt{c};
    }

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

