package API::Command::GetDownloadCurrentStatements;
use strict;
use warnings;

use Apache2::Const qw(OK FORBIDDEN HTTP_OK HTTP_UNAUTHORIZED HTTP_NOT_FOUND HTTP_NOT_IMPLEMENTED);

use File::Temp;

use lib '/app/tools/common/lib';
use Common::RSApp;
use RSApache::Response::DownloadZipDirectory;
use Common::DB::Item::PayeeType;

use lib '/app/tools/api/lib';
use API::Response;
use API::DB::Item::PortalPayee;
use API::Util;

use lib '/app/tools/rps/lib';
use RPS::RoyaltyRun::Status;
use RPS::Statement::Artist::StatementFull;
use RPS::Statement::Mechanical::US::PDF;
use RPS::Statement::Mechanical::US::Text;
use RPS::Statement::Mechanical::US::StatementFull;
use RPS::ArtistRoyalty::ArtistRoyaltyRun;
use RPS::Mechanical::US::MechanicalRun;

use RPS::DB::Item::ArtistRoyaltyStatement;
use RPS::DB::Item::MechanicalStatement;

use base 'API::Command::StatementBase';

sub area { return "client"; }
sub cmd  { return "statement"; }

# This command is the endpoint for downloading current statements that this user has access to.

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

    # Make sure we have a valid session
    my $response = $self->SUPER::execute();
    return $response if ($response);

    my $clientID = $self->getRouteParam(":clientId")  || 0;
    my $runType  = $self->getRouteParam(":runTypeId") || '';
    my $format   = lc( $self->getParam("format")      || "pdf" );

    my $userID    = $self->{userID};                            # derived from session (see SUPER::execute)
    my $payeeType = $self->getPayeeTypeByRunType($runType);     # convert runType to payeeType

    my $errorResponse = $self->_validate($userID, $clientID, $runType);
    return $errorResponse if $errorResponse;

    my $oClient    = Common::DB::Item::Client->Lookup( client_id => $clientID );
    my $clientName = API::Util->cleanName( $oClient->display_name );

    my $appSingleton = Common::RSApp->new_temporary( clientID => $clientID );
    my $dbo = Common::RSApp::GetClientDB();

    # create temporary directory for statement files
    $ENV{HOME}     = '/';
    my $tmpDirPath = "/tmp/$runType" . "_$$" . $clientID . "_XXXXXXXX";
    my $tempdir    = File::Temp::tempdir( $tmpDirPath, CLEANUP => 1 );

    my $portalCollection = API::DB::Item::PortalPayee->GetAllConfirmedByUserIDPayeeType($userID, $payeeType);
    while ( $portalCollection->hasNext() ) {
        my $oPortalPayee = $portalCollection->next();
        next unless $oPortalPayee->client_id == $clientID;

        # only peyees/recipients with required client_id will reach this point
        my $aStatements = $self->_getStatements($runType, $oPortalPayee);

        my $error = $self->_prepareStatementFiles(
            $clientName, $clientID, $format, $runType, $tempdir, $oPortalPayee, $aStatements
        );
        last && return $error if $error;
    }

    my $response = $self->_downloadArchive($userID, $tempdir, $runType);
    return $response if $response;

    return $self->createResponse(
        status => HTTP_OK,
        data   => { msg => "no statement(s) found" }
    );
}

sub _validate {
    my ($self, $userID, $clientID, $runType) = @_;

    # Make sure user can access client (e.g., does a valid portal user exist?)
    if( !$self->canAccess($userID, $clientID) ) {
        return $self->createResponse(
            status => HTTP_UNAUTHORIZED,
            data   => { msg => "user not authorized for client $clientID" }
        );
    }

    my $allowedRunTypes = join '|', $self->getAllowedRunTypes();

    unless ( $runType =~ /^(?:$allowedRunTypes)$/ ) {
        return $self->createResponse(
            status => HTTP_NOT_IMPLEMENTED,
            data   => { msg => "Invalid runtype" }
        );
    }

    return;
}

sub _getStatements {
    my ($self, $runType, $oPortalPayee) = @_;

    my ($aStatements) = $self->getStatementData( 'current', $oPortalPayee, $runType );
    return $aStatements;
}

sub _prepareStatementFiles {
    my ($self, $clientName, $clientID, $format, $runType, $tempdir, $oPortalPayee, $aStatements) = @_;

    foreach my $hStatement (@$aStatements) {
        # filtering statements for additional recipients
        next unless $self->_canRecipientUserSeeStatement( $oPortalPayee, $hStatement );

        my $stmtID = $hStatement->{statement_id};

        if ( $runType =~ /^artist$/i ) {
            my $oStatement = RPS::DB::Item::ArtistRoyaltyStatement->Lookup( artist_royalty_statement_id => $stmtID );
            return $self->createResponse(
                status => HTTP_NOT_IMPLEMENTED,
                data   => { msg => "Non existent statement" }
            ) unless $oStatement;

            $self->_getArtistStatementFile( $clientName, $clientID, $format, $tempdir, $runType, $oStatement );
        } elsif ( $runType =~ /^publisher$/i ) {
            my $oStatement = RPS::DB::Item::MechanicalStatement->Lookup( mechanical_statement_id => $stmtID );
            return $self->createResponse(
                status => HTTP_NOT_IMPLEMENTED,
                data   => { msg => "Non existent statement" }
            ) unless $oStatement;

            $self->_getPublisherStatementFile( $clientName, $clientID, $format, $tempdir, $runType, $oStatement );
        }
    }

    return;
}

sub _getArtistStatementFile {
    my ($self, $clientName, $clientID, $format, $tempdir, $runType, $oStatement) = @_;

    my $runID        = $oStatement->artist_royalty_run_id;
    my $baseFilePath = RPS::Statement::Artist::PDF::StatementPathFromRunID($runID);
    my $clientPrefix = $clientName . '__run_' . $runID;

    if ( $format =~ /^pdf|all$/i ) {
        my $prettyFileName = RPS::Statement::Artist::PDF::PrettyStatementFileNameFromDBItem($oStatement);
        $prettyFileName = $clientPrefix . '__' . $prettyFileName;

        my $uglyFileName = RPS::Statement::Artist::PDF::StatementFileNameFromDBItem($oStatement);
        system("ln -s $baseFilePath/$uglyFileName $tempdir/$prettyFileName");
    }

    if ( $format =~ /^xls|all$/i ) {
        my $prettyFileName = RPS::Statement::Artist::Excel::PrettyStatementFileNameFromDBItem($oStatement);
        $prettyFileName = $clientPrefix . '__' . $prettyFileName;

        my $uglyFileName = RPS::Statement::Artist::Excel::StatementFileNameFromDBItem($oStatement);
        system("ln -s $baseFilePath/$uglyFileName $tempdir/$prettyFileName");
    }

    return 1;
}

sub _getPublisherStatementFile {
    my ($self, $clientName, $clientID, $format, $tempdir, $runType, $oStatement) = @_;

    my $runID        = $oStatement->mechanical_run_id;
    my $baseFilePath = RPS::Statement::Mechanical::US::PDF->StatementPathFromRunID($runID);
    my $clientPrefix = $clientName . '__run_' . $runID;

    if ( $format =~ /^pdf|all$/i ) {
        my $prettyFileName = RPS::Statement::Mechanical::US::PDF->PrettyStatementFileNameFromDBItem($oStatement);
        $prettyFileName = $clientPrefix . '__' . $prettyFileName;

        my $uglyFileName = RPS::Statement::Mechanical::US::PDF->StatementFileNameFromDBItem($oStatement);
        system("ln -s $baseFilePath/$uglyFileName $tempdir/$prettyFileName");
    }

    if ( $format =~ /^txt|all$/i ) {
        my $prettyFileName = RPS::Statement::Mechanical::US::Text->PrettyStatementFileNameFromDBItem($oStatement);
        $prettyFileName = $clientPrefix . '__' . $prettyFileName;

        my $uglyFileName = RPS::Statement::Mechanical::US::Text->StatementFileNameFromDBItem($oStatement);
        system("ln -s $baseFilePath/$uglyFileName $tempdir/$prettyFileName");
    }

    return 1;
}

sub _downloadArchive {
    my ($self, $userID, $tempdir, $runType) = @_;

    my $userObj = AppUser::DB::Item::User->Lookup(
        user_id   => $userID
    );

    my $userName = $userObj->first_name . '_' . $userObj->last_name;
    $userName = API::Util->cleanName($userName);

    my $contentType = 'application/octet-stream';
    my $zipFileName = $userName . '__' . $runType . "_statement.zip";
    my $response = RSApache::Response::DownloadZipDirectory->new( $tempdir, $contentType, $zipFileName );

    return $response;
}

sub _canRecipientUserSeeStatement {
    my ($self, $oPayee, $hStatementData) = @_;

    # it is not an additional payee statement recipient
    return 1 unless $oPayee->statement_recipient_id;

    my $dateInvited = $oPayee->date_invited;
    my $runDate     = $hStatementData->{date};
    # the recipient was invited before the run was committed or at the same time
    return 1 if $runDate ge $dateInvited;

    return 0;
}


1;
