#------------------------------------------------------------
# Copyright (C) 2009 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------

package RPS::Mechanical::UK::Process::CreateStatement;

# This class will serve as the base class for the processes that create
# MCPS statements.  There should be a fair amount of common code, so that
# will go here.
#
# The basic idea is the overall 'flow' will be defined here.  Meaning, the
# essential steps will be encapsulated as abstract methods which subclasses
# will override.  And there will be a 'createStatement' method that is implemented
# here in terms of these abstract methods.
#
use strict;

use lib '/app/tools/common/lib';
use lib '/app/tools/rps/lib';
use lib '/app/tools/raptor/lib';
use Raptor::DB::Item::File;
use Data::Dumper;
use Common::Log;
use Common::Assert;
use Common::Util;
use RPS::DB::Item::McpsStatement;
use RPS::DB::Item::UKMechanicalRun;
use RPS::DB::Item::SaleRunMap;
use RPS::DB::Item::McpsLicenseRun;
use RPS::DB::Item::Product;
use RPS::DB::Item::Album;
use RPS::DB::Item::Track;
use RPS::DB::Item::Artist;
use RPS::DB::Item::MechanicalRunMissedSaleLog;

use RPS::Mechanical::Process::CreateStatement;

use base 'RPS::Mechanical::Process::CreateStatement';


sub _runType
{
    my ($self) = @_;
    return RPS::DB::Item::SaleRunMap::kRunTypeUKMechanical;
}


sub _statementItemToID
{
    my ($self, $statementItem) = @_;

    return $statementItem->mcps_statement_item_id();
}

sub _idFromStatementItem
{
    my ($self, $statementItem) = @_;

    return $statementItem->mcps_statement_item_id();
}

sub _getRunDBItem
{
    my ($self) = @_;

    my $statement = $self->_getStatementDBItem();
    my $runID = $statement->uk_mechanical_run_id;
    my $run = RPS::DB::Item::UKMechanicalRun->Lookup(uk_mechanical_run_id => $runID);
    return $run;
}

sub _runID
{
    my ($self) = @_;

    if (! $self->{_runID})
    {
        my $run = $self->_getRunDBItem();
        $self->{_runID} = $run->uk_mechanical_run_id;
    }
    return $self->{_runID};
}


sub _payorID
{
    my ($self) = @_;

    if (! $self->{_payorID})
    {
        my $run = $self->_getRunDBItem();
        $self->{_payorID} = $run->payor_id;
    }

    return $self->{_payorID};
}


sub _processLicense
{
    my ($self, $license) = @_;

    $self->SUPER::_processLicense($license);

    # 'flag' this license as having been involved in this run.
    #
    my $mapEntry = RPS::DB::Item::McpsLicenseRun->Create
    (
        mcps_license_id => $license->mcps_license_id(),
        uk_mechanical_run_id => $self->_runID(),
    );
    $mapEntry->save();
}



sub _getSaleIDs
{
    my ($self) = @_;

    # !!! We'll probably have a different accessor in the Sale class for each
    # !!! type of statement.  So I don't think there will be any inherited behavior.
    #
    die "ERROR - You must overload _getSaleIDs";
}


sub _liquidateRetention
{
    my ($self, $retention) = @_;

    my $item = $self->_getStatementItemForRetention($retention);

    # Liquidating retentions are stored as _negative_ numbers...
    #
    my $currentValue = $item->retentions();
    $item->retentions($currentValue - $retention->units_held());
}


sub _updateStatementItemWithSale
{
    my ($self, $statementItem, $sale) = @_;

    die "OVERLOAD _updateStatementItemWithSale\n";
}

sub _processSaleWithLicenses
{
    my ($self, $sale, $licenses, $processedSales) = @_;


    # For UK licenses, this is easy - Just skip the sale if it appears in this hash
    #
    return if $processedSales->{$sale->sale_id};

    foreach my $license (@$licenses)
    {
        # This is sort-of a hack, to support the weirdness that is the AVP licensing stuff.
        # If we're here, then we have found a license.  But, it might not be the _right king_ of license.
        # In that case, we just want to skip this sale and move on (and not mark the sale as 'bad').
        # This is because if it matches a license, _somebody_ is going to be processing that sale.
        if (! $self->_licenseTypeMatches($license))
        {
            $self->_report("  found license, but it's not _our_ license", 4);
            $self->_report($license, 4);
            return;
        }

        # Fetch the statement item associated with this license (on this statement, obviously).
        # !!! This call should create a new one if necessary.
        #
        my $statementItem = $self->_getStatementItemForSale($license, $sale);


        # Update the statement item with data from this sale.
        #
        $self->_updateStatementItemWithSale($statementItem, $sale);

        $self->_markSalePaid($sale, $statementItem);
    }
}

sub _logSaleException
{
    my ($self, $exception) = @_;


    # Dereference the stuff inside the exception object.
    #
    my $sale = $exception->sale();
    my $reason = $exception->error();
    my $details = $exception->details();


    # Expand the details a bit to include more hints about the offending sale to the user.
    #
    if ($sale)
    {
        my $fileID = $sale->file_id;
        if ($fileID)
        {
            my $file = Raptor::DB::Item::File->Lookup(file_id => $fileID);
            if ($file && $file->orig_file_name)
            {
                $details .= " : sales file \"" . $file->orig_file_name . "\"";

                if ($sale->line_num)
                {
                    $details .= " : line_num " . $sale->line_num;
                }
            }
        }
    }

    my $product = RPS::DB::Item::Product->Lookup(product_id => $sale->product_id);

    my $albumID;
    if ($product->product_type_id == RPS::DB::Item::Product::kProductTypeDigitalTrack)
    {
        my $track = RPS::DB::Item::Track->Lookup(track_id => $product->asset_id);
        if ($track)
        {
            $albumID = $track->album_id;
        }
    }
    else
    {
        $albumID = $product->asset_id;
    }

    my $albumTitle;
    my $artistName;
    my $catalogNumber;

    if ($albumID)
    {
        my $album = RPS::DB::Item::Album->Lookup(album_id => $albumID);
        if ($album)
        {
            $catalogNumber = $album->catalog_number;
            $albumTitle = $album->title;

            my $artist = RPS::DB::Item::Artist->Lookup(artist_id => $album->artist_id);
            if ($artist)
            {
                $artistName = $artist->name;
            }
        }
    }


    # Missed sale log...!!! Now I believe we ought to have a 'run type' column here instead, and
    # make this generic.
    #
    my $logEntry = RPS::DB::Item::MechanicalRunMissedSaleLog->Create
    (
        mechanical_run_id => $self->_runID(),
        run_type => $self->_runType(),
        reason => $reason,
        details => $details,
        sale_id => $sale->sale_id,
        album_id => $albumID,
        artist_name => $artistName,
        album_title => $albumTitle,
        catalog_number => $catalogNumber,
        product_id => $sale->product_id,
        product_type_id => $product->product_type_id,
        units => ($sale->sales() - $sale->returns()),
    );
    $logEntry->save();
}



1;
