#------------------------------------------------------------
# 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();
}

sub _readSaleLicenseMap {
    my ( $self, $saleIDs ) = @_;
    $self->_report( "RSD7859 Not implemented for UK mechanicals");
} # _readSaleLicenseMap

sub _readSalePublisherLicenseMap {
    my ( $self, $statement ) = @_;
    $self->_report( "RSD7859 Not implemented for UK mechanicals");
} # _readSalePublisherLi

sub _isASubPublisher {
    my ( $self, $statement ) = @_;
    # RSD7859 doesn't apply to UK mechanicals, but this method will get referenced
    # in the base class and throw an error if not defined.
    return 0;
}

sub _findMatchingLicensesFast {
    my ( $self, $sale ) = @_;
    # RSD7859 doesn't apply to UK mechanicals, but this method will get referenced
    # in the base class and throw an error if not defined.
    return $self->_findMatchingLicenses( $sale );
}

1;
