#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;
use Date::Calc qw(Days_in_Month);
use POSIX qw(strftime);
use File::Basename;
use Getopt::Long;

use lib '/app/tools/raptor/lib';
use Raptor::Config;
use Raptor::Tracker::Job::ImportOrchardSalesFile;

use lib '/app/tools/rps/lib';
use RPS::File::File;

use lib '/app/tools/data_classes/lib';
use File::File;

use lib '/app/tools/common/lib';
use Common::RSDB;
use Common::RSApp;
use Common::Log;
use Common::DB::Item::OrchardClient;
use Common::DB::Item::OrchardReport;
use Common::OrchardFetcher::OrchardPeriod;

my $prog = basename($0);

my %args;
parseCommandLine( \%args );

# By default, we'll process the entire accounting statement as received from
# The Orchard.  If the "-t" option is present, then all downloaded reports
# will be truncated to 100 lines before we start importing into RPS.
# THIS OPTION IS FOR TESTING ONLY.
#
my $truncate = $args{truncate};

my $logLevel = $args{logLevel};
Log->init( level => 'error' );
Log->setLogLevel($logLevel) if ($logLevel);

my @orchardClients;

# We need a reference to RSApp in order to connect to RSCOMMON
#
my $appSingleton = Common::RSApp->new( clientID => 202 );    # 202 = RSTEST
my $cdbo         = Common::RSApp::GetCommonDB();
my $dbh          = $cdbo->DBH;

# Get the Orchard client info from RSCOMMON ...
#
my %clientInfo = ();
my $coll       = Common::DB::Item::OrchardClient->GetAll();
while ( $coll->hasNext() ) {
    my $c = $coll->next;

    next if( $c->status == 0 ); # skip clients with integration disabled

    $clientInfo{ $c->client_id }{ $c->account_id }{user_id}       = $c->user_id;
    $clientInfo{ $c->client_id }{ $c->account_id }{status}        = $c->status;
    $clientInfo{ $c->client_id }{ $c->account_id }{scan_schedule} = $c->scan_schedule;
    $clientInfo{ $c->client_id }{ $c->account_id }{start_period}  = $c->start_period;
}

my $config     = Raptor::Config->new();
my $scriptPath = $config->get('sale_import_script_dir');

my $currentDate = strftime "%Y-%m-%d", localtime;
my ( $currentYear, $currentMonth, $currentDay ) = split( '-', $currentDate );

my %periodInfo = Common::OrchardFetcher::OrchardPeriod::getPeriodHash($currentYear);

Log->info("$prog: ####### Scanning Orchard accounts on $currentDate");

undef $appSingleton;

foreach my $clientID ( sort { $a <=> $b } keys %clientInfo ) {

    # Need the singleton so that we can import files on the client's behalf
    #
    my $appSingleton = Common::RSApp->new( clientID => $clientID );
    my $dbo = Common::RSApp::GetClientDB();

    my $accountInfo = $clientInfo{$clientID};

    foreach my $accountID ( sort { $a <=> $b } keys %$accountInfo ) {

        my $userID      = $clientInfo{$clientID}{$accountID}{user_id};
        my $status      = $clientInfo{$clientID}{$accountID}{status};
        my $schedule    = $clientInfo{$clientID}{$accountID}{scan_schedule};
        my $startPeriod = $clientInfo{$clientID}{$accountID}{start_period};
        if ( $status == Common::DB::Item::OrchardClient::kStatusIgnore ) {
            Log->info("fetch_orchard.pl: --- Skipping client $clientID  account $accountID  user $userID  status $status  schedule $schedule");
            next;
        } else {
            Log->info("fetch_orchard.pl: --- Scanning client $clientID  account $accountID  user $userID  status $status  schedule $schedule");
        }

        foreach my $id ( sort { $a <=> $b } keys %periodInfo ) {
            my $period     = $periodInfo{$id}{period};
            my $periodName = $periodInfo{$id}{period_name};
            my $startDate  = $periodInfo{$id}{start_date};
            my $endDate    = $periodInfo{$id}{end_date};


            next if ( $startDate gt $currentDate );
            next if ( $schedule == 1 && $period =~ /,/ );    # skip quarter period if schedule is monthly
            next if ( $schedule == 2 && $period !~ /,/ );    # skip month period if schedule is quarterly

            if ( $period =~ /,/ ) {
                my ( $p0, $p1, $p2 ) = split( ',', $period );
                next if ( $p0 < $startPeriod );
            } else {
                next if ( $period < $startPeriod );
            }

            if ( $currentDate ge $startDate && $currentDate le $endDate ) {

                # Skip the period if the current date falls within the period
                #
                # Note: just because a date falls past a period's end date doesn't
                # mean that you will be able to successfully query or generate a report
                # for the period.  The period must be enabled or booked by the Orchard
                # in order for the accounting API to successfully perform operations
                # against it.
                #
                next;
            }

            # Setup the command to ping OWS for a period report
            #
            my $cmd = "nice $scriptPath/fetch_orchard_report.pl -c $clientID -p $period -a $accountID -u $userID";
            if ( $status && $status == Common::DB::Item::OrchardClient::kStatusCanQuery ) {
                $cmd .= " -g";    # Add "-g" (generate) option to command
            }

            $cmd .= " -t"           if ($truncate);
            $cmd .= " -l $logLevel" if ($logLevel);

            # Check if we have a local report entry for the period.  These get created
            # when we first start looking for the report, and get updated as the report
            # is processed by the ingestion process.  An RPS file_id is assigned to the
            # report once we have a file ready to import.  If we don't have a report
            # entry or if we have one without a file_id then we'll query OWS for the
            # report.
            #
            my $report = Common::DB::Item::OrchardReport->Lookup( client_id => $clientID, account_id => $accountID, period => $period );

            if ( !$report || ( $report && !$report->file_id ) ) {

                # Call the 'fetch_orchard_report.pl' script to look for the report
                # on OWS.
                #
                # The script will create an 'orchard_report' entry for the client/period
                # if it doesn't exist, and update the status field of the entry as it's
                # processed by RPS.
                #
                # if the report exists:
                #  - download it to the local filesystem
                #  - unpack the file
                #  - merge file parts if it's in multiple pieces
                #  - upload into RPS (this creates an RPS file_id)
                # if report doesn't exist
                #   if client has permission, go ahead and submit a request
                #
                #
                `$cmd`;    # ping OWS for report data

                # Report was created (or updated); get current data. The report may
                # or may not have an RPS file_id, depending on whether the Orchard
                # statement was found, downloaded, and uploaded into RPS.
                #
                $report = Common::DB::Item::OrchardReport->Lookup( client_id => $clientID, account_id => $accountID, period => $period );

            }

            my $reportID = $report->report_id;
            my $st       = $report->status;
            my $fileID   = $report->file_id;

            if ( !$fileID ) {
                my $st = $report->status;
                Log->warn( "fetch_orchard.pl: $clientID : No fileID found for reportID $reportID "
                      . "[period $period status=$st ("
                      . Common::DB::Item::OrchardReport->printStatus($st)
                      . ")]" );
                next;
            }

            if ( $st == Common::DB::Item::OrchardReport::kFileImportReady ) {
                my $jobArgs = Raptor::Tracker::Job::ImportOrchardSalesFile->new( fileID => $fileID );
                my $job     = $jobArgs->enqueue();
                my $jobID   = $jobArgs->{JobID};

                Log->debug( "fetch_orchard.pl: created job $jobID : " . Dumper($jobArgs) );

                $report->status(Common::DB::Item::OrchardReport::kFileQueued);
                $report->job_id($jobID);
                $report->save();
            } else {
                Log->info( "fetch_orchard.pl: $clientID : Skipping reportID $reportID "
                      . "[period $period status=$st ("
                      . Common::DB::Item::OrchardReport->printStatus($st)
                      . ")]" );

                # Has the file status changed since we queued up the import job?
                # Update the report status if so.  Setting the status to kFileImported
                # just means that the import job finished; the actual import may (or may
                # not) have any errors.
                #
                if ( $st == Common::DB::Item::OrchardReport::kFileQueued ) {
                    my $o = RPS::File::File->new( file_id => $fileID );

                    if (   $o->FileStatus != File::File::STATUS_NEW
                        && $o->FileStatus != File::File::STATUS_PROCESSING ) {
                        $report->status(Common::DB::Item::OrchardReport::kFileImported);
                        $report->notes( "file $fileID imported with status " . $o->FileStatus );
                        $report->save();
                    }
                }
            }

        }    # period loop

    }    # account loop

}    # client loop

sub parseCommandLine {
    my ($a) = @_;
    my $truncate;
    my $logLevel;
    die if (
        !GetOptions(
            't|truncate'   => \$truncate,
            'l|loglevel=s' => \$logLevel,
        )
    );
    $a->{truncate} = $truncate;
    $a->{logLevel} = $logLevel;
}

1;
