package BookPub::Tracker::Command::RevenueFileLibrary;
use strict;
use warnings;

use lib '/app/tools/bookpub/lib';
use lib '/app/tools/common/lib';
use RSApache::Response::XSLT;
use Common::Assert;
use Date::Calc ();
use BookPub::Tracker::Service;
use BookPub::Tracker::File::Display;
use BookPub::DB::Item::File;
use BookPub::DB::Item::Service;

use base 'BookPub::Command';

sub cmd      { return "revenue_file_library"; }
sub area     { return "tracker"; }
sub pageName { return 'Revenue File Library'; }

use constant kTemplate    => '/app/tools/bookpub/templates/tracker/revenue_file_library.xsl';
use constant kSplitTemplate => '/app/tools/bookpub/templates/tracker/ajax_split_history.xsl';
use constant kSortDateCreated => 'date_created';
use constant kSortDatePeriodClosed => 'period_date_closed';

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

    my $oResponse = $self->SUPER::execute();
    return $oResponse if $oResponse;

    my $fileID        = $self->getParam('file')         || '';
    my $popup         = $self->getParam('popup')        || '';
    my $page          = $self->getParam('page')         || 1;
    my $serviceID     = $self->getParam('serviceID')    || 0;
    my $dateType      = $self->getParam('dateType')     || 'received';
    my $prevDateType  = $self->getParam('prevDateType') || $dateType;
    my $startDate     = $self->getParam('startDate')    || '';
    my $endDate       = $self->getParam('endDate')      || '';
    my $pageSize      = $self->getParam('pageSize')     || 25;
    my $defaultSortBy = $dateType eq 'received' ? kSortDateCreated : kSortDatePeriodClosed;
    my $sortBy        = $self->getParam('sortBy')       || $defaultSortBy;
    my $reverseSort   = $self->getParam('reverseSort')  // 1;

    if ( $popup eq 'split_history' ) {
        return $self->_renderSplitHistory($fileID);
    }

    if ( $prevDateType ne $dateType ) {
        $sortBy = $defaultSortBy;
        $reverseSort = 1;
    }

    $self->_setParamsXml(
        file => $fileID,
        page => $page,
    );

    $self->_setFormXml(
        serviceID   => $serviceID,
        dateType    => $dateType,
        startDate   => $startDate,
        endDate     => $endDate,
        pageSize    => $pageSize,
        sortBy      => $sortBy,
        reverseSort => $reverseSort,
    );

    my $parsedStartDate = $self->_convertDateFormat($startDate);
    my $parsedEndDate   = $self->_convertDateFormat($endDate);

    if (   ( $startDate && !$self->_isValidParsedDate($parsedStartDate) )
        || ( $endDate && !$self->_isValidParsedDate($parsedEndDate) )
        || ( $parsedStartDate && $parsedEndDate && $parsedStartDate gt $parsedEndDate  ) ) {
        $self->addMessageXML( type => 'error', code => 'invalid_revenue_file_library_date' );
        $self->_setResultsXml(
            files        => [],
            page         => $page,
            pageCount    => 1,
            totalRecords => 0,
        );

        return RSApache::Response::XSLT->new( $self->{xml}, kTemplate );
    }

    my $oFiles = BookPub::DB::Item::File->SearchByDateRange(
        service_id  => $serviceID,
        date_type   => $dateType,
        start_date  => $parsedStartDate,
        end_date    => $parsedEndDate,
        sort_by     => $sortBy,
        sort_desc   => $reverseSort,
    );

    my ( $totalRecords, $pageCount ) = $self->_paginateFiles( $oFiles, $page, $pageSize );

    $self->_setResultsXml(
        files        => $self->_getFileRows($oFiles),
        page         => $page,
        pageCount    => $pageCount,
        totalRecords => $totalRecords,
    );

    return RSApache::Response::XSLT->new( $self->{xml}, kTemplate );
}

sub _renderSplitHistory {
    my ( $self, $fileID ) = @_;
    assert($fileID);

    my $oSelectedFile = BookPub::DB::Item::File->Lookup( file_id => $fileID );
    assert($oSelectedFile);

    my $oRootFile    = $self->_getRootFile($oSelectedFile);
    my $oRootDisplay = BookPub::Tracker::File::Display->new( dbItem => $oRootFile );

    $self->{xml}{SplitInfo}{ServiceName}      = $oRootDisplay->{ServiceName};
    $self->{xml}{SplitInfo}{OriginalFileName} = $oRootFile->orig_file_name;
    $self->{xml}{SplitInfo}{File}             = $self->_getSplitChainRows($oRootFile);

    return RSApache::Response::XSLT->new( $self->{xml}, kSplitTemplate );
}

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

    my @services = (
        {
            serviceID   => 0,
            serviceName => 'All Services',
        }
    );

    my $oAllServices = BookPub::DB::Item::Service->GetAllWithFilesSortedByName();
    while ( my $oService = $oAllServices->next() ) {
        push @services,
            {
                serviceID   => $oService->service_id,
                serviceName => $oService->service_name,
            };
    }

    return \@services;
}

sub _setParamsXml {
    my ( $self, %args ) = @_;

    $self->{xml}{Params}{file} = $args{file};
    $self->{xml}{Params}{page} = $args{page};

    return;
}

sub _setFormXml {
    my ( $self, %args ) = @_;

    $self->{xml}{Form}{ServiceID}   = $args{serviceID};
    $self->{xml}{Form}{DateType}    = $args{dateType};
    $self->{xml}{Form}{StartDate}   = $args{startDate};
    $self->{xml}{Form}{EndDate}     = $args{endDate};
    $self->{xml}{Form}{PageSize}    = $args{pageSize};
    $self->{xml}{Form}{SortBy}      = $args{sortBy};
    $self->{xml}{Form}{ReverseSort} = $args{reverseSort};
    $self->{xml}{Form}{ServiceList}{Service} = $self->_getAllServices();

    return;
}

sub _setResultsXml {
    my ( $self, %args ) = @_;

    $self->{xml}{Results}{File}         = $args{files};
    $self->{xml}{Results}{page}         = $args{page};
    $self->{xml}{Results}{pageCount}    = $args{pageCount};
    $self->{xml}{Results}{totalRecords} = $args{totalRecords};

    return;
}

sub _paginateFiles {
    my ( $self, $oFiles, $page, $pageSize ) = @_;

    if ( $pageSize ne 'all' ) {
        $oFiles->setPagination( pageIndex => $page, pageSize => $pageSize );
    }

    my $totalRecords = $oFiles->totalSize;
    my $pageCount = $oFiles->numPages || 1;
    return ( $totalRecords, $pageCount );
}

sub _getFileRows {
    my ($self, $oFiles) = @_;

    my @fileRows;
    while ( my $oFileItem = $oFiles->next() ) {
        my $oFile = BookPub::Tracker::File::Display->new( dbItem => $oFileItem );
        my ( $periodID, $periodName, $closedDate ) = $self->_getPeriodInfo($oFileItem);
        my $parentFileID = $oFile->{ParentFileID} || 0;
        my $hasChild     = $oFile->{HasChild} || 0;
        my $isSplit      = $self->_isSplitFile( $parentFileID, $hasChild );

        push @fileRows, {
            FileID                  => $oFileItem->file_id,
            ServiceName             => $oFile->{ServiceName},
            FileName                => $oFile->{PrettyFileName},
            VersionNum              => $oFile->{VersionNum},
            Received                => $oFile->{DateCreated},
            Units                   => $oFile->{Units},
            Revenue                 => $oFile->{Revenue},
            RevenueBase             => $oFile->{RevenueBase},
            CurrencyCode            => $oFile->{CurrencyCode},
            InputRevenue            => $oFile->{InputRevenue},
            InputConversionRate     => $oFile->{InputConversionRate},
            ConversionInput         => $oFile->{AlternateConversionInput} || 0,
            ParentFileID            => $oFile->{ParentFileID},
            HasChild                => $oFile->{HasChild},
            AlternateConversionRate => $oFile->{AlternateConversionRate},
            AlternateCurrencyCode   => $oFile->{AlternateCurrencyCode},
            AlternateCurrencyList   => $oFile->{AlternateCurrencyList},
            Records                 => $oFile->{Records},
            PeriodID                => $periodID,
            PeriodName              => $periodName,
            Closed                  => $closedDate,
            FileStatus              => $oFile->{FileStatus},
            Notes                   => $oFile->{Notes},
            IsSplit                 => $isSplit,
        };
    }

    return \@fileRows;
}

sub _isSplitFile {
    my ( $self, $parentFileID, $hasChild ) = @_;

    return ( $parentFileID || $hasChild ) ? 1 : 0;
}

sub _getRootFile {
    my ( $self, $oFile ) = @_;

    while ( $oFile->parent_file_id ) {
        $oFile = BookPub::DB::Item::File->Lookup( file_id => $oFile->parent_file_id );
    }

    return $oFile;
}

sub _getSplitChainRows {
    my ( $self, $oRootFile ) = @_;

    my @rows;
    my $oFile = BookPub::DB::Item::File->LookupWithPeriodInfo( file_id => $oRootFile->file_id );

    while ($oFile) {
        my $oDisplay = BookPub::Tracker::File::Display->new( dbItem => $oFile );
        my ( $periodID, $periodName, $closedDate ) = $self->_getPeriodInfo($oFile);

        push @rows, {
            FileID   => $oFile->file_id,
            FileName => $oDisplay->{PrettyFileName},
            Received => $oDisplay->{DateCreated},
            PeriodID => $periodID,
            Period   => $periodName,
            Closed   => $closedDate,
        };

        $oFile = BookPub::DB::Item::File->LookupWithPeriodInfo( parent_file_id => $oFile->file_id );
    }

    return \@rows;
}

sub _getPeriodInfo {
    my ( $self, $oFile ) = @_;

    my $periodID = $oFile->period_id;
    $periodID = 0 unless defined $periodID && $periodID =~ /^\d+$/;

    my $periodName = $oFile->{period_name} || '';
    $periodName .= ' (Current)' if $periodID == 0;

    my $closedDate = $oFile->{period_date_closed} || '';

    return ( $periodID, $periodName, $closedDate );
}

sub _convertDateFormat {
    my ( $self, $date ) = @_;
    return '' unless $date;

    my $dateTimeFormat = Common::Client::Current()->Locale()->dateTimeFormat();
    my $parsedDate = $dateTimeFormat->parseDate($date);

    return $parsedDate;
}

sub _isValidParsedDate {
    my ( $self, $parsedDate ) = @_;
    return 0 unless $parsedDate;

    my ( $year, $month, $day ) = $parsedDate =~ /^(\d+)-(\d+)-(\d+)$/;
    return 0 unless defined $year && defined $month && defined $day;

    return Date::Calc::check_date( $year, $month, $day ) ? 1 : 0;
}


1;
