#!/usr/bin/perl
#------------------------------------------------------------
# Copyright (C) 2006-2012 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#------------------------------------------------------------
use strict;

#use warnings;

use Data::Dumper;
use Getopt::Std;
use Carp;

use lib '/app/tools/common/lib';
use Common::Assert;
use Common::RSMath;
use Common::Locale;
use Common::Client;

use lib '/app/tools/rps/lib';
use RPS::Statement::Artist::StatementFull;
use RPS::DB::Item::ClientOptions;
use RPS::DB::Item::ContractRateType;
use RPS::DB::Item::IncomeSource;
use RPS::DB::Item::Region;
use RPS::DB::Item::Channel;
use RPS::DB::Item::PriceLevel;
use RPS::DB::Item::NewArtistContract;

use lib '/app/tools/rps/bin/statements';
use Formats;

$SIG{__DIE__} = \&Carp::confess;

# This determines how much output we spew forth to STDERR.
# The user can set this with the -V command-line argument.
#
my $gVerbosityLevel = 1;

# Parse the command-line, then create the CSV!
#
my %options;
parseCommandLine( \%options );

processArtistRunText( $options{clientID}, $options{artistRunID}, $options{artistStatementID}, $options{outputPath} );

# ----------------------------------------------------------------------------------------------

sub processArtistRunText {
    my ( $clientID, $runID, $statementID, $outFilePath ) = @_;

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

    # This report is intended to be run after the statements have been
    # generated, so the output path should already exist.

    # Create the output path if it isn't there already.
    #
    if ( '/' ne substr( $outFilePath, -1, 1 ) ) {
        $outFilePath .= "/";
    }

    if ( !-d $outFilePath ) {
        mkpath($outFilePath) or die "ERROR: Unable to create path $outFilePath: $!\n";
    }

    # Get rid of the semaphore file
    my $semaphore = $outFilePath . "EXPORT_AB_TEXT_COMPLETE";
    unlink($semaphore);

    my $targetFile = $outFilePath . "ab_export_run_$runID.txt";

    open( my $outFile, ">" . $targetFile );
    binmode( $outFile, ':utf8' );

    my $revenueTotalHeader = 'net-revenue-total';
    if ( RPS::DB::Item::ClientOptions->Get( 'gross_revenue' )) {
        $revenueTotalHeader = 'revenue-total';
    }

    # Write out column headings.
    my @headings = (
        'payee-name',                   # A
        'client-no',                    # B
        'rs-payee-id',                  # C
        'album-title',                  # D
        'album-artist',                 # E
        'catalog-no',                   # F
        'client-album-id',              # G
        'rs-album-id',                  # H
        'contract-name',                # I
        'rs-contract-id',               # J
        'cross-collateralize',          # K
        'unit-level-income',            # L
        $revenueTotalHeader,            # M
        'license-income-total',         # N
        'recoupable-expenses-total',    # O
        'net-expenses-total',           # P
        'album-previous-balance',       # Q
        'album-total',                  # R
        'contract-date-modified',       # S
        'album-custom-1',               # T
        'album-custom-2',               # U
        'album-custom-3',               # V

    );

    my $header = join( "\t", @headings );
    print $outFile "$header\n";

    # Get the collection of statements for this run.
    #
    my $statements = RPS::DB::Item::ArtistRoyaltyStatement->GetByArtistRoyaltyRunIDSortedForAlbumBalancesReport($runID);
    while ( my $statement = $statements->next() ) {
        my $_stmtID = $statement->artist_royalty_statement_id;
        next if ( $statementID && $_stmtID != $statementID );

        processStatementText( $outFile, $_stmtID );
    }

    # All done, close it up.
    #
    close $outFile;

    # Create the semaphore
    #
    open SEMAPHORE, "> $semaphore";
    print SEMAPHORE "done\n";
    close SEMAPHORE;

}    #processArtistRunText

sub processStatementText {
    my ( $outFile, $artistStatementID ) = @_;

    # Instantiate the Artist Statement object.
    # This object will contain all (most of) the info we need to output the statement document.
    #
    my $statement = RPS::Statement::Artist::StatementFull->new( artistRoyaltyStatementID => $artistStatementID, );

    details( $statement, $outFile );
}

sub details {
    my ( $statement, $outFile ) = @_;

    my $albumList = $statement->ArtistStatementAlbumList()->getList();
    foreach my $album (@$albumList) {

        # We need to skip the albums whose income items use the non-payable rate type exclusively.
        #
        my $incomeItemList = $album->IncomeItemList()->getList();
        my $skipAlbum      = 1;
        foreach my $incomeItem (@$incomeItemList) {
            if ( $incomeItem->ContractRateTypeID() != RPS::DB::Item::ContractRateType::kRateTypeNonPayable ) {
                $skipAlbum = 0;
                last;
            }
        }

        # If there are no sales, then we're dealing with license income
        # and/or expenses, which should be included on the statement.
        #
        if (   @$incomeItemList == 0
            || $album->PreviousBalance() != 0
            || $album->LicenseIncomeSubtotal() != 0
            || $album->TotalExpenses() != 0 ) {
            $skipAlbum = 0;
        }

        if ( $skipAlbum == 1 ) {
            next;
        }

        my $rsContractID         = $album->ArtistContractID();
        my $contract             = RPS::DB::Item::NewArtistContract->Lookup( artist_contract_id => $rsContractID );
        my $contractDateModified = $contract->date_modified;

        #----------------------------------------
        # Generate report line with album info
        #----------------------------------------
        my @reportRow = (
            $statement->ArtistPayee()->Name(),               # A - payee-name
            $statement->ArtistPayee()->ClientAccountID(),    # B - client-no
            $statement->ArtistPayee()->ArtistPayeeID(),      # C - rs-payee-id
            $album->Album()->Title(),                        # D - album-title
            $album->Album()->ArtistName(),                   # E - album-artist
            $album->Album()->CatalogNumber(),                # F - catalog-no
            $album->Album()->ClientAlbumID(),                # G - client-album-id
            $album->Album()->AlbumID(),                      # H - rs-album-id
            $album->ContractName(),                          # I - contract-name
            $album->ArtistContractID,                        # J - rs-contract-id
            $album->IsCrossCollateralized() ? 'yes' : 'no',  # K - cross-collateralize
            $album->UnitLevelIncome(),                       # L - unit-level-income
            $album->NetRevenueIncome(),                      # M - net-revenue-total
            $album->LicenseIncomeSubtotal(),                 # N - license-income-total
            $album->RecoupableExpenses(),                    # O - recoupable-expenses-total
            $album->NetRevenueExpensesSubTotal(),            # P - net-expenses-total
            $album->PreviousBalance(),                       # Q - album-previous-balance
            $album->Total(),                                 # R - album-total
            $contractDateModified,                           # S - contract-date-modified
            $album->Album()->Custom1(),                      # T - album-custom-1
            $album->Album()->Custom2(),                      # U - album-custom-2
            $album->Album()->Custom3(),                      # V - album-custom-3
        );
        my $joinedReportRow = join( "\t", @reportRow );
        print $outFile "$joinedReportRow\n";

    }    #album loop

}    #details

# For now, we are not realy going to be doing any formatting of numbers.
#

sub formatNumber {
    my ($value) = @_;

    #$value = Formats::formatNumber($value);

    return $value;
}

sub formatMoney {
    my ($value) = @_;

    #$value = Formats::formatMoney($value);

    return $value;
}

sub formatPercent {
    my ($value) = @_;

    #$value = Formats::formatPercent($value);

    return $value;
}

# These functions map ids to their text representations.
# Basically, the first time we ask for a particular id->string mapping, we
# will query the correct database, and build a hash.  Subsequent calls just
# hit the hash.
#
# Because these tables are so similar, I abstracted the guts into the _genericMapAccessor
# method (to save myself some typing).
#
my %idMaps;

sub _genericMapAccessor {
    my ( $collectionAccessor, $idName, $id ) = @_;

    if ( !defined $idMaps{$collectionAccessor} ) {
        $idMaps{$collectionAccessor} = {};

        # This is a very naughty thing to do, but it works great in this context.
        #
        #        no strict 'refs';
        #        my $c = &$collectionAccessor();
        #        use strict 'refs';
        my $c = $collectionAccessor->GetAll();

        while ( my $item = $c->next() ) {
            if ( $idName ne 'product_type_id' ) {
                $idMaps{$collectionAccessor}{ $item->$idName() } = $item->name;
            } else {
                $idMaps{$collectionAccessor}{ $item->$idName() } =
                  $item->description;
            }
        }
    }

    return $idMaps{$collectionAccessor}{$id};
}

sub incomeSourceIDToName {
    my ($id) = @_;
    return _genericMapAccessor( 'RPS::DB::Item::IncomeSource', 'income_source_id', $id );
}

sub channelIDToName {
    my ($id) = @_;

    #return "All" if( 0 == $id );
    return _genericMapAccessor( 'RPS::DB::Item::Channel', 'channel_id', $id );
}

sub priceLevelIDToName {
    my ($id) = @_;

    #return "All" if( 0 == $id );
    return _genericMapAccessor( 'RPS::DB::Item::PriceLevel', 'price_level_id', $id );
}

sub contractRateTypeIDToName {
    my ($id) = @_;
    return _genericMapAccessor( 'RPS::DB::Item::ContractRateType', 'contract_rate_type_id', $id );
}

sub regionIDToName {
    my ( $id, $defaultRate ) = @_;

    if ( $id == 0 && $defaultRate == 1 ) {
        return 'All';
    } else {
        return _genericMapAccessor( 'RPS::DB::Item::Region', 'region_id', $id );
    }
}

#
# Boring script stuff below...
#

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

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

    if ( !$opt{r} || !$opt{c} ) {
        usage();
        exit(1);
    }
    $settings->{artistRunID}       = $opt{r};
    $settings->{clientID}          = $opt{c};
    $settings->{outputPath}        = $opt{p};
    $settings->{artistStatementID} = $opt{s};

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

sub usage {
    print STDERR "\nusage: $0 -c <client_id> -r <artist_run_id> [-p <output path>]\n";
    print STDERR "\n";
    print STDERR "Arguments:\n";
    print STDERR "\t-c <client_id>\t\t\tThe client_id of the client to process\n";
    print STDERR "\t-r <artist_royalty_run_id>\tThe id of the artist run to generate export data for\n";
    print STDERR "\t-p <output path>\tThe output path. Optional. If not provided, use current directory.\n";
}

sub report {
    my ( $string, $verbosity ) = @_;
    $verbosity = 1 unless defined $verbosity;

    if ( $gVerbosityLevel >= $verbosity ) {
        print STDERR $string . "\n";
    }
}

