#!/usr/bin/perl

use strict;
use POSIX qw(ceil);

use lib '/app/tools/common/lib';

use Getopt::Std;
use Common::Consts;

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

use lib '/app/tools/data_classes/lib';
use File::File;
use Client::Service;

use lib '/app/tools/sale_import/lib';
use Sale::File;

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

use lib '/app/tools/rps/lib';
use RPS::DB::Item::Track;
use RPS::DB::Item::TrackLicense;
use RPS::DB::Item::LicenseReserve;
use RPS::DB::Item::Album;
use RPS::DB::Item::AlbumContract;
use RPS::DB::Item::ControlledComposition;
use RPS::DB::Item::ReserveLiquidation;
use RPS::DB::Item::NewArtistContractTerm;
use RPS::DB::Item::NewArtistContract;
use RPS::DB::Item::ArtistContractTermReserve;
use RPS::DB::Item::ArtistContractTermReserveRun;
use RPS::DB::Item::LicenseReserveRun;


my $licenseReserveSQL = "CREATE TABLE `license_reserve` ("
."`license_reserve_id` int(10) unsigned NOT NULL auto_increment,"
."`track_license_id` int(10) unsigned NOT NULL default '0',"
."`original_statement_item_id` int(10) unsigned NOT NULL default '0',"
."`product_id` int(10) unsigned NOT NULL default '0',"
."`sale_stat_rate_id` int(10) unsigned NOT NULL default '0',"
."`issue_stat_rate_id` int(10) unsigned NOT NULL default '0',"
."`units` int(10) NOT NULL default '0',"
."`effective_rate` decimal(8,4) unsigned NOT NULL default '0.0000',"
."`periods_remaining` tinyint(3) unsigned NOT NULL default '0',"
."`date_created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,"
."`date_modified` timestamp NOT NULL default '0000-00-00 00:00:00',"
."PRIMARY KEY  (`license_reserve_id`),"
."KEY `track_license_id` (`track_license_id`),"
."KEY `product_id` (`product_id`),"
."KEY `original_statement_item_id` (`original_statement_item_id`)"
.") ENGINE=MyISAM DEFAULT CHARSET=latin1;";

my $artistContractTermReserveSQL = "CREATE TABLE `artist_contract_term_reserve` ("
."`artist_contract_term_reserve_id` int(10) unsigned NOT NULL auto_increment,"
."`artist_contract_term_id` int(10) unsigned NOT NULL default '0',"
."`income_source_id` int(10) unsigned NOT NULL default '0',"
."`region_id` int(10) unsigned NOT NULL default '0',"
."`channel_id` int(10) unsigned NOT NULL default '0',"
."`price_level_id` int(10) unsigned NOT NULL default '0',"
."`original_statement_item_id` int(10) unsigned NOT NULL default '0',"
."`product_id` int(10) unsigned NOT NULL default '0',"
."`product_format_id` int(10) unsigned NOT NULL default '0',"
."`units` int(10) unsigned NOT NULL default '0',"
."`revenue` decimal(16,4) NOT NULL default '0.0000',"
."`price` decimal(16,4) NOT NULL default '0.0000',"
."`revenue_based` tinyint(1) unsigned NOT NULL default '0',"
."`effective_rate` decimal(8,4) unsigned NOT NULL default '0.0000',"
."`periods_remaining` tinyint(3) unsigned NOT NULL default '0',"
."`date_created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,"
."`date_modified` timestamp NOT NULL default '0000-00-00 00:00:00',"
."PRIMARY KEY  (`artist_contract_term_reserve_id`),"
."KEY `artist_contract_term_id` (`artist_contract_term_id`),"
."KEY `original_statement_item_id` (`original_statement_item_id`)"
.") ENGINE=MyISAM DEFAULT CHARSET=latin1;";


my @clientIDs;
push @clientIDs, _getLocalClientIDs();

#foreach my $clientID (@clientIDs) {
foreach my $clientID (14) {
    next unless ($clientID);
    print $clientID."\n";


    my $app = Common::RSApp->new(clientID => $clientID);

    _convertMechanicalReserves();
    _convertArtistRoyaltyReserves();
}


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

    # First, we need to read the current reserve table.
    # I don't think I can rely on the DB::Item class to work here.
    # We'll read the entire thing into memory.
    #
    my @oldReserves;
    my $sth = $dbo->DoCmd("SELECT * FROM license_reserve");
    while (my $hr = $sth->fetchrow_hashref())
    {
        push @oldReserves, $hr;
    }

    # Now we drop the table, and re-create it.
    # !!! Actually... let's rename the table so we have a fallback.
    #
    $dbo->DoCmd("RENAME TABLE license_reserve TO old_license_reserve");
    $dbo->DoCmd($licenseReserveSQL);


    # Loop through the old reserves and create appropriate new reserves.
    #
    foreach my $oldReserve (@oldReserves)
    {
        # We need to get the original liquidation schedule.
        #
        my $trackLicenseID = $oldReserve->{track_license_id};
        my $trackLicense = RPS::DB::Item::TrackLicense->Lookup(track_license_id => $trackLicenseID);

        my $reserveID;
        my $reserveType;
        if (RPS::DB::Item::TrackLicense::kPublishingLicense == $trackLicense->type)
        {
            $reserveID = $trackLicenseID;
            $reserveType = RPS::DB::Item::ReserveLiquidation::kTypePublishingLicense;
        }
        elsif (RPS::DB::Item::TrackLicense::kControlledComposition == $trackLicense->type)
        {
            # !!! Pretty weird - Why do we get that from the track id, rather than from the
            # track license?
            # This seems to only be used to fetch the liquidation schedule.
            # !!! Therefore, it's going to be going away anyway.
            #
            $reserveID = _getControlledCompIDFromTrackID($trackLicense->track_id);
            $reserveType = RPS::DB::Item::ReserveLiquidation::kTypeControlledComposition;
        }


        # Get the associated run id(s).
        #
        my @reserveRunIDs;
        my $mapItems = RPS::DB::Item::LicenseReserveRun->GetAll("select * from license_reserve_run where license_reserve_id=".$oldReserve->{license_reserve_id});
        while (my $mapItem = $mapItems->next())
        {
            push @reserveRunIDs, $mapItem->mechanical_run_id;
        }

        my %scheduleTable;
        my $schedule = RPS::DB::Item::ReserveLiquidation->GetByIDType($reserveID, $reserveType);

        while ($schedule->hasNext())
        {
            my $scheduleEntry = $schedule->next();
            $scheduleTable{$scheduleEntry->period} = $scheduleEntry->percent;
        }


        # Now we can finally create the new reserves.
        #
        my $units = $oldReserve->{initial_units};
        for (my $i = 1; $units > 0 && $i <= 8; $i++)
        {
            my $p = $scheduleTable{$i};
            next unless $p;

            my $periodUnits = ceil($oldReserve->{initial_units} * ($p / 100));
            $periodUnits = $units unless $periodUnits < $units;

            $units -= $periodUnits;


            # If we've already done this period, we don't need to create the reserve.
            #
            my $periodsRemaining = 1 + ($i - $oldReserve->{next_period});
            next if $periodsRemaining < 1;


            # Create the new reserve
            #
            my $newReserve = RPS::DB::Item::LicenseReserve->Create
            (
                track_license_id => $oldReserve->{track_license_id},
                original_statement_item_id => $oldReserve->{original_statement_item_id},
                product_id => $oldReserve->{product_id},
                sale_stat_rate_id => $oldReserve->{sale_stat_rate_id},
                issue_stat_rate_id => $oldReserve->{issue_stat_rate_id},
                units => $periodUnits,
                effective_rate => $oldReserve->{effective_rate},
                periods_remaining => $periodsRemaining,
            );

            $newReserve->save();

            # Create a new mapping table entry, too
            #
            foreach my $runID (@reserveRunIDs)
            {
                my $newMap = RPS::DB::Item::LicenseReserveRun->Create(license_reserve_id => $newReserve->license_reserve_id, mechanical_run_id => $runID);
                $newMap->save();
            }
        }
    }

}


sub _convertArtistRoyaltyReserves
{
    my ($clientID) = @_;

    my $dbo = Common::RSApp::GetClientDB();

    # First, we need to read the current reserve table.
    # I don't think I can rely on the DB::Item class to work here.
    # We'll read the entire thing into memory.
    #
    my @oldReserves;
    my $sth = $dbo->DoCmd("SELECT * FROM artist_contract_term_reserve");
    while (my $hr = $sth->fetchrow_hashref())
    {
        push @oldReserves, $hr;
    }

    # Now we drop the table, and re-create it.
    # !!! Actually... let's rename the table so we have a fallback.
    #
    $dbo->DoCmd("RENAME TABLE artist_contract_term_reserve TO old_artist_contract_term_reserve");
    $dbo->DoCmd($artistContractTermReserveSQL);


    # Loop through the old reserves and create appropriate new reserves.
    #
    foreach my $oldReserve (@oldReserves)
    {
        my $termID = $oldReserve->{artist_contract_term_id};

        # Need to fetch the contract id, from the term.
        #
        my $term = RPS::DB::Item::NewArtistContractTerm->Lookup(artist_contract_term_id => $termID);
        my $contract = RPS::DB::Item::NewArtistContract->Lookup(artist_contract_id => $term->artist_contract_id);

        # Get the associated run id(s).
        #
        my @reserveRunIDs;
        my $mapItems = RPS::DB::Item::LicenseReserveRun->GetAll("select * from artist_contract_term_reserve_run where artist_contract_term_reserve_id =".$oldReserve->{artist_contract_term_reserve_id});
        while (my $mapItem = $mapItems->next())
        {
            push @reserveRunIDs, $mapItem->artist_royalty_run_id;
        }

        my %scheduleTable;

        my $schedule = RPS::DB::Item::ReserveLiquidation->GetByIDType($term->artist_contract_id, RPS::DB::Item::ReserveLiquidation::kTypeArtistContract);

        while ($schedule->hasNext())
        {
            my $scheduleEntry = $schedule->next();
            $scheduleTable{$scheduleEntry->period} = $scheduleEntry->percent;
        }


        # Now we can finally create the new reserves.
        # !!! Need to take units and revenue into account.
        #
        my $units = $oldReserve->{initial_units};
        my $revenue = $oldReserve->{initial_revenue};
        for (my $i = 1; ($units > 0 || $revenue > 0) && $i <= 8; $i++)
        {
            my $p = $scheduleTable{$i};
            next unless $p;

            my $periodUnits = ceil($oldReserve->{initial_units} * ($p / 100));
            $periodUnits = $units unless $periodUnits < $units;
            $units -= $periodUnits;

            my $periodRevenue = ceil($oldReserve->{initial_revenue} * ($p / 100));
            $periodRevenue = $revenue unless $periodRevenue < $revenue;
            $revenue -= $periodRevenue;

            # If we've already done this period, we don't need to create the reserve.
            #
            my $periodsRemaining = 1 + ($i - $oldReserve->{next_period});
            next if $periodsRemaining < 1;


            # Create the new reserve
            #
            my $newReserve = RPS::DB::Item::ArtistContractTermReserve->Create
            (
                artist_contract_term_id => $oldReserve->{artist_contract_term_id},
                income_source_id => $oldReserve->{income_source_id},
                region_id => $oldReserve->{region_id},
                channel_id => $oldReserve->{channel_id},
                price_level_id => $oldReserve->{price_level_id},
                original_statement_item_id => $oldReserve->{original_statement_item_id},
                product_id => $oldReserve->{product_id},
                product_format_id => $oldReserve->{product_format_id},
                units => $periodUnits,
                revenue => $periodRevenue,
                price => $oldReserve->{price},
                revenue_based => $oldReserve->{revenue_based},
                effective_rate => $oldReserve->{effective_rate},
                periods_remaining => $periodsRemaining,
            );

            $newReserve->save();

            # Create a new mapping table entry, too
            #
            foreach my $runID (@reserveRunIDs)
            {
                my $newMap = RPS::DB::Item::ArtistContractTermReserveRun->Create(artist_contract_term_reserve_id => $newReserve->artist_contract_term_reserve_id, artist_royalty_run_id => $runID);
                $newMap->save();
            }
        }

    }

}


sub _getLocalClientIDs
{
    # We have a nifty little script that will give us a list of client databases.
    #
    my $clientListString = `/app/tools/rps/bin/db/list_client_dbs.pl`;
    chomp $clientListString;


    # Find the client id that matches each database.
    #
    my @ids;
    my @dbNames = split(/ /, $clientListString);
    foreach my $dbName (@dbNames)
    {
        my $id = Common::RSDB::DBNameToClientID($dbName);
        push @ids, $id;

    }

#    return @ids;
    return 14;
}

sub _getControlledCompIDFromTrackID
{
    my ($track_id) = @_;

    my $track = RPS::DB::Item::Track->Lookup(track_id => $track_id);
    my $albumID = $track->album_id;


    my $albumContract = RPS::DB::Item::AlbumContract->GetCComp($albumID);
    return undef unless $albumContract;
                                        
    my $cc = RPS::DB::Item::ControlledComposition->GetByContractID($albumContract->artist_contract_id);
    return $cc->controlled_composition_id;
}
