#!/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::Client;
use Common::RSDB;
use Common::RSMath;

use lib '/app/tools/rps/lib';
use RPS::DB::Item::MechanicalRunTrackLicense;
use RPS::DB::Item::ProductType;
use RPS::DB::Item::Album;
use RPS::DB::Item::Track;
use RPS::DB::Item::Artist;
use RPS::DB::Item::Product;
use RPS::DB::Item::Master;
use RPS::DB::Item::Label;
use RPS::DB::Item::MechanicalRunUnlicensedTrackLog;

my $gVerbosityLevel = 1;

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

my $clientID = $options{clientID};
assert($clientID);
my $runID = $options{runID};
assert($runID);

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

_report("\n---- Client $clientID");
_report("\n---- Run $runID");

my $runType = 'MECH';

my %missingShareMap;
my $allItems = RPS::DB::Item::MechanicalRunTrackLicense->GetByRunIDAndType( $runID, $runType );
while ( my $item = $allItems->next() ) {
    push @{ $missingShareMap{ $item->track_id }{ $item->product_id }{ $item->track_license_id } },
      {
        share => $item->share,
        units => $item->units,
        rate  => $item->base_rate,
      };
}

# Now build the report
#
foreach my $trackID ( keys %missingShareMap ) {
    my $track = _getTrack($trackID);
    _report("\n---- looking for track $trackID");
    if ( defined($track) ) {
        _report("\n---- found track $trackID");
        my $album    = _getAlbum( $track->album_id );
        my $label    = _getLabel( $album->label_id );
        my $master   = _getMaster( $track->master_id );
        my $duration = $master->duration;
        my $isrc     = $master->isrc;

        #next if ($track->mechanical_exempt);

        # !!! Can't assume that there _is_ a track artist, oddly.
        #
        my $trackArtist;
        my $trackArtistName = '';
        if ( $track->artist_id ) {
            $trackArtist = _getArtist( $track->artist_id );
        }

        if ( defined($trackArtist) ) {
            $trackArtistName = $trackArtist->name;
        }

        my $productIDHash = $missingShareMap{$trackID};
        foreach my $productID ( keys %$productIDHash ) {
            my %rateUnitHash;

            my $totalShare;

            my $product = _getProduct($productID);
            my $upc     = $product->upc_ean;

            my $productTypeID = $product->product_type_id;
            my $productType   = _getProductType($productTypeID);
            $productType = $productType->description;

            my $trackLicenseIDHash = $productIDHash->{$productID};
            foreach my $trackLicenseID ( keys %$trackLicenseIDHash ) {
                my $share;

                my $dataArray = $trackLicenseIDHash->{$trackLicenseID};
                foreach my $data (@$dataArray) {
                    my $units = $data->{units};

                    # !!! Making an assumption here, that this is the same for all data items that
                    # !!! hashed to this location.
                    #
                    $rateUnitHash{ $data->{rate} } += $data->{units};
                    $share = $data->{share};
                }

                $totalShare += $share;
            }

            if ( $totalShare < 99 ) {
                my $missingShare = 100 - $totalShare;
                my $totalOwed;
                foreach my $baseRate ( keys %rateUnitHash ) {
                    my $units = $rateUnitHash{$baseRate};
                    my $rate = Common::RSMath::round( $baseRate * ( $missingShare / 100 ), 4 );
                    $totalOwed += Common::RSMath::round( $units * $rate, 2 );
                }

                my $log = _createUnlicensedTrackLogEntry( $runID, $album, $label, $track, $trackArtistName, $isrc, $upc, $productType,
                    $missingShare, $totalOwed );

                if ($log) {
                    $log->save();
                }
            }
        }
    }
}

sub _createUnlicensedTrackLogEntry {
    my ( $runID, $album, $label, $track, $trackArtistName, $isrc, $upc, $productType, $missingShare, $totalOwed ) = @_;

    # Skip tracks that are mechanical exempt
    #
    return if ( $track->mechanical_exempt );

    my $log = RPS::DB::Item::MechanicalRunUnlicensedTrackLog->Create(
        mechanical_run_id => $runID,
        label_id          => $album->label_id,
        label_name        => $label->label_name,
        catalog_number    => $album->catalog_number,
        track_id          => $track->track_id,
        album_id          => $album->album_id,
        album_title       => $album->title,
        track_artist_name => $trackArtistName,
        track_title       => $track->title,
        isrc              => $isrc,
        upc_ean           => $upc,
        product_type      => $productType,
        unlicensed_share  => $missingShare,
        accrual           => $totalOwed
    );

    return $log;
}

sub _getTrack {
    my ($trackID) = @_;

    return RPS::DB::Item::Track->Lookup( track_id => $trackID );
}

sub _getAlbum {
    my ($albumID) = @_;

    return RPS::DB::Item::Album->Lookup( album_id => $albumID );
}

sub _getProduct {
    my ($productID) = @_;
    assert($productID);

    return RPS::DB::Item::Product->Lookup( product_id => $productID );
}

sub _getLabel {
    my ($labelID) = @_;
    assert($labelID);

    return RPS::DB::Item::Label->Lookup( label_id => $labelID );
}

sub _getArtist {
    my ($artistID) = @_;
    assert($artistID);

    return RPS::DB::Item::Artist->Lookup( artist_id => $artistID );
}

sub _getProductType {
    my ($productTypeID) = @_;
    assert($productTypeID);

    return RPS::DB::Item::ProductType->Lookup( product_type_id => $productTypeID );
}

sub _getMaster {
    my ($masterID) = @_;

    return RPS::DB::Item::Master->Lookup( master_id => $masterID );
}

sub _usage {
    print "\nusage: $0 -c client_id -r run_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-r <run_id>\t\tThe run_id of the run 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 $string . "\n";
    }
}

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

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

    $settings->{clientID} = $opt{c} if $opt{c};
    $settings->{runID}    = $opt{r} if $opt{r};

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