#!/usr/bin/perl
use strict;

# -----------------------------------------
# input params:
#
# 	- client_id
# 	- file_id
#
# -----------------------------------------
# what it does:
#
# 	- get file record from db
# 	- if status is NEW or IN_QUEUE
# 		- change status to PROCESSING
# 		- set import_pid to this pid ($$)
# 		- import file
# 		- if success
# 			- change status to OPEN
#		- else
#			- fail?
#	- elsif status is PROCESSING
#		- if import_pid is not running
#			- try to re-import file
#		- else
#			- do nothing
#	- else
#		- do nothing
#
# -----------------------------------------

use lib '/app/tools/common/lib';
use Common::RSDB;
use Common::Log;
use Common::Email;
use Common::Flattery::FlatteryBot;
use Common::RSApp;
use Common::DB::Item::Client;
use Common::DB::Item::MapFaceFile;

use lib '/app/tools/data_classes/lib';
use Client::Service;
use Client::Client;

use lib '/app/tools/raptor/lib';
use Raptor::DB::Item::Sale;

use lib '/app/tools/rps/lib';
use RPS::File::File;
use RPS::MapFace::Mapper;
use RPS::Sale::File;
use RPS::Sale::File::EMI::YouTubeMonthly;
use RPS::DB::Item::Service;
use RPS::DB::Item::MapFaceTempMapping;
use RPS::DB::Item::SaleImportError;

use lib '/app/tools/common/lib';
use Common::Util;
use Common::RSApp;
use Common::Log;

use lib '/app/tools/appuser/lib';
use AppUser::User::User;

use FindBin;
use constant SANCTUARY => 31;

import_sales_file();

sub import_sales_file {
    my $debug         = 0;
    my $continue      = 0;
    my $orchardNotify = 0;

    # Match a leading argument of -d / --debug / -c / --continue
    while ( $ARGV[0] =~ m/^\-{1,2}([dco])/ ) {
        if    ( $1 eq 'd' ) { $debug         = 1; }
        elsif ( $1 eq 'c' ) { $continue      = 1; }
        elsif ( $1 eq 'o' ) { $orchardNotify = 1; }
        shift @ARGV;
    }

    my $client_id = $ARGV[0] or return usage("no client id passed");
    my $file_id   = $ARGV[1] or return usage("no file id passed");

    my $service_id = $ARGV[2];
    my $version    = $ARGV[3];
    my $file_path  = $ARGV[4];

    if ( $service_id || $version ) {
        return usage('both service_id AND version_num must be supplied, or neither at all') unless ( $service_id && $version );
    }

    # Instantiate the Application Singleton object.  This will initialize our global environment.
    #
    my $appSingleton = Common::RSApp->new( clientID => $client_id );

    $debug && Common::Log::LOGGER->setLogLevel('debug');

    my $file = RPS::File::File->new( file_id => $file_id, client_id => $client_id );
    if ( !$file || $file->FileID != $file_id ) {
        return usage("File $file_id was not found.");
    }

    # - if status is NEW
    #
    if ( File::File::STATUS_NEW() == $file->FileStatus || File::File::STATUS_IN_QUEUE() ) {
      IMPORT:

        # - change status to PROCESSING
        # - set import_pid to this pid ($$)
        $file->FileStatus(File::File::STATUS_PROCESSING);
        $file->ImportPID($$);
        $file->Save();

        unless ( Common::Util::is_interactive() ) {
            print STDERR scalar localtime() . "-running as: '$FindBin::Bin/$FindBin::Script @ARGV'\n";
        }

        # - parse sales file
        # !!! Inserting some abstraction in here.
        # !!! To experiment with stream-based parsing for these massive EMI YouTube files.
        #
        my $sf;

        #        if ($file->OrigFileName() =~ /^YTB.*monthly\.txt$/)
        if ( Client::Client::kEMI == $client_id ) {

            # !!! The client_id parameter is pointless...
            #
            $sf = RPS::Sale::File::EMI::YouTubeMonthly->new( client_id => $client_id );
        } else {
            $sf = RPS::Sale::File->new( client_id => $client_id );
        }

        my $success = $sf->ParseFull(
            client_id  => $client_id,
            file       => $file,
            service_id => $service_id,
            version    => $version,
            file_path  => $file_path,
        );
        my $error = $sf->errstr;

        # Let's make sure the file wasn't deleted during processing.
        # If it was, we just need to call delete on it to get rid of all of the related entries.
        if ( Raptor::DB::Item::File->Lookup( file_id => $file_id ) ) {
            if ( !$error ) {

                # Let's look for the first non-qualifying error for this file.
                # These will only exist if the importer has been updated for MapFace.
                my $nonqualifyingErrors = RPS::DB::Item::SaleImportError->GetAllNonqualifyingByFileID($file_id);
                if ( $nonqualifyingErrors && $nonqualifyingErrors->size() > 0 ) {

                    # We just need to grab the first one at this point, to display it on the tracker page.
                    my $nonqualifyingError = $nonqualifyingErrors->next();
                    $error = $nonqualifyingError->description;

                    my $sale = Raptor::DB::Item::Sale->Lookup( sale_id => $nonqualifyingError->sale_id );
                    if ($sale) {
                        $error .= " (line: " . $sale->{line_num} . ")";
                    }
                }
            }

            if ( $success && !length $error ) {

                # For MapFace importers (should come up empty for all non-MapFace ones)
                my $unmappedErrorCount = RPS::DB::Item::SaleImportError->GetUnmappedCountByFileID($file_id);

                # no_save so we only make one db hit, not two
                $file->UpdateSummary( no_save => 1 );

                # files with no records are just placeholders so they can be closed
                # also need to clear the md5sum so other empty files won't match
                if ( $file->Records() == 0 ) {
                    print STDERR "empty file\n";
                    $file->Revenue(0);
                    $file->Units(0);
                    $file->FileStatus(File::File::STATUS_OPEN);
                    $file->MD5Sum('null');
                } elsif ( $unmappedErrorCount && $unmappedErrorCount > 0 ) {

                    # If a file has unmapped errors, it goes to the on-hold section.
                    $file->FileStatus(File::File::STATUS_ON_HOLD);
                    $file->MD5Sum( Common::Util::md5sum( $file->FileDir . '/' . $file->FileName ) ) unless $file->MD5Sum;

                    my $service = RPS::DB::Item::Service->Lookup( service_id => $file->ServiceID );

                    # If we mapped something during the import process, let's not count it as an
                    # "initial error".  Users won't be able to navigate to it anyway.
                    my $initialErrors = RPS::DB::Item::MapFaceTempMapping->GetNonAutoApprovedCountByFileID($file_id);

                    # We also need to add an entry to the mapface_file table in RSCOMMON
                    # so that it will show up in the list on the mapface admin page.
                    my $mapFaceFile = Common::DB::Item::MapFaceFile->Create(
                        client_id        => $client_id,
                        service_id       => $file->ServiceID,
                        service_name     => $service->service_name,
                        file_id          => $file->FileID,
                        version_num      => $file->VersionNum,
                        orig_file_name   => $file->OrigFileName,
                        date_created     => $file->DateCreated,
                        initial_errors   => $initialErrors,
                        remaining_errors => $initialErrors,
                    );

                    $mapFaceFile->save();

                    # Also, we need to send an email to the user that uploaded this file.
                    print STDERR "file placed on hold, notifying user and support\n";

                    # Note that if we're processing an Orchard file, we'll suppress the
                    # MapFace user notification (support will still get the email though).
                    #
                    _onHoldNotificationUser($file) if ( !$orchardNotify );

                    if (Common::RSApp::IsProductionServer) {
                        _onHoldNotificationSupport($mapFaceFile);
                    }
                } else {
                    $file->FileStatus(File::File::STATUS_OPEN);
                    $file->MD5Sum( Common::Util::md5sum( $file->FileDir . '/' . $file->FileName ) ) unless $file->MD5Sum;

                    if ($orchardNotify) {
                        _onValidOrchardNotifyUser($file);    # send success email
                    }
                }

                if ( my $error = $sf->errstr ) {
                    $file->Notes($error);
                    print STDERR "The file was imported with error(s): $error\n";

                    if ($orchardNotify) {
                        _onInvalidOrchardNotifyUser($file);
                        _onInvalidOrchardNotifySupport($file);
                    }
                }

                $file->DateProcessed( Common::Util::today_and_now() );
                $file->Save();
            } else    # import failed or had errors
            {
                if ($error) {
                    $file->Notes($error);
                    print STDERR "error during parsing: $error\n";

                    if ($orchardNotify) {
                        _onInvalidOrchardNotifyUser($file);
                        _onInvalidOrchardNotifySupport($file);
                    }
                }

                $file->FileStatus(File::File::STATUS_INVALID);
                $file->Save();

                # the file will remain in processing status
            }
        } else {

            # Delete it (along with all of the assorted records related to it).
            $file->Delete();
        }
    }

    #	- elsif status is PROCESSING
    elsif ( File::File::STATUS_PROCESSING() == $file->FileStatus ) {
        my $process = $file->ImportPID;

        # h don't print header
        # p lookup by pid
        my @running = `ps hp $process`;

        if (@running) {
            return usage("File $file_id is still being processed.");
        } else {
            goto IMPORT;
        }
    }
}

sub _onHoldNotificationUser {
    my $file = shift;

    my $serviceName;
    my $service = RPS::DB::Item::Service->Lookup( service_id => $file->ServiceID );
    if ($service) {
        $serviceName = "for " . $service->service_name;
    }

    my $user = AppUser::User::User->new( userID => $file->UserID );
    if ( $user && $user->Email ) {
        my $to      = $user->Email;
        my $from    = 'do-not-reply@royaltyshare.com';
        my $subject = "Sales File On Hold $serviceName";
        my $url =
            "https://"
          . Common::RSApp::GetClientVHost()
          . ".royaltyshare.com/app/tracker?Highlight="
          . $file->FileID . "#file"
          . $file->FileID;
        my $body = "A file you uploaded has encountered unknown data while processing:  $url

RoyaltyShare Support has been notified and is working to update our system to allow the file to process.

You will receive an email when the file has been processed successfully.

Thank you,

RoyaltyShare Support";

        Common::Email->SendAWS(
            to      => $to,
            from    => $from,
            subject => $subject,
            body    => $body
        );
    }
}

sub _onHoldNotificationSupport {
    my $mapFaceFile = shift;

    my $client = Common::DB::Item::Client->Lookup( client_id => $mapFaceFile->client_id );
    my $clientName = $client->client_name;

    my $serviceName;
    my $service = RPS::DB::Item::Service->Lookup( service_id => $mapFaceFile->service_id );
    if ($service) {
        $serviceName = $service->service_name;
    }

    my $versionNum = $mapFaceFile->version_num;

    my $subject = "MapFace Errors for $clientName: $serviceName v$versionNum";

    my $to   = 'filebot@royaltyshare.com';
    my $from = 'fileissues@royaltyshare.com';

    my $clientURL = "https://" . Common::RSApp::GetClientVHost() . ".royaltyshare.com";
    my $mapFaceURL =
      "https://" . Common::RSApp::GetClientVHost() . ".royaltyshare.com/rps/mapface?Highlight=" . $mapFaceFile->mapface_file_id;
    my $resolveURL =
      "https://" . Common::RSApp::GetClientVHost() . ".royaltyshare.com/rps/mapface?c=map&file=" . $mapFaceFile->file_id . "&map=1";
    my $fileName = $mapFaceFile->orig_file_name;

    my $flattery = Common::Flattery::FlatteryBot->acquireFlattery( flatteryAmount => 1 );

    my $body = "A new file was added to the mapping queue at " . $mapFaceFile->date_created . ": $mapFaceURL

File name: $fileName

Customer website: $clientURL

Go here to view and resolve these errors: $resolveURL

And remember, FlatteryBot says: $flattery

Now, go resolve some errors!";

    Common::Email->SendAWS(
        to      => $to,
        from    => $from,
        subject => $subject,
        body    => $body
    );
}

# Nofify user if import was successful (FB17903).
#
sub _onValidOrchardNotifyUser {
    my $file = shift;

    my $serviceName;
    my $service = RPS::DB::Item::Service->Lookup( service_id => $file->ServiceID );
    if ($service) {
        $serviceName = "for " . $service->service_name;
    }
    my $fileName = $file->OrigFileName;

    my $user = AppUser::User::User->new( userID => $file->UserID );
    if ( $user && $user->Email ) {
        my $to      = $user->Email;
        my $subject = "Orchard File Successfully Processed";
        my $url =
            "https://"
          . Common::RSApp::GetClientVHost()
          . ".royaltyshare.com/app/tracker?Highlight="
          . $file->FileID . "#file"
          . $file->FileID;
        my $body = "The Orchard file $fileName has been automatically uploaded to your RoyaltyShare website.

Click here to go to the Revenue tab to view the file: $url

Thank you,

RoyaltyShare Support";

        Common::Email->SendAWS(
            to      => $to,
            subject => $subject,
            body    => $body
        );
    }
}    # _onValidOrchardNotifyUser

# Nofify user if error was found (FB18134).
#
sub _onInvalidOrchardNotifyUser {
    my $file = shift;

    my $serviceName;
    my $service = RPS::DB::Item::Service->Lookup( service_id => $file->ServiceID );
    if ($service) {
        $serviceName = "for " . $service->service_name;
    }

    my $user = AppUser::User::User->new( userID => $file->UserID );
    if ( $user && $user->Email ) {
        my $to      = $user->Email;
        my $subject = "Orchard Sales File Error";
        my $url =
            "https://"
          . Common::RSApp::GetClientVHost()
          . ".royaltyshare.com/app/tracker?Highlight="
          . $file->FileID . "#file"
          . $file->FileID;
        my $body = "A recent Orchard sales file automatically uploaded to your site has encountered an error: $url

RoyaltyShare Support has been notified and is working to update our system to allow the file to process.

You will receive an email when the file has been processed successfully.

Thank you,

RoyaltyShare Support";

        Common::Email->SendAWS(
            to      => $to,
            subject => $subject,
            body    => $body
        );
    }
}    # _onInvalidOrchardNotifyUser

# Nofify support if error was found (FB18134).
#
sub _onInvalidOrchardNotifySupport {
    my $file = shift;

    my $client = Common::DB::Item::Client->Lookup( client_id => Common::RSApp::GetClientID() );
    my $clientName = $client->client_name;

    my $serviceName;
    my $service = RPS::DB::Item::Service->Lookup( service_id => $file->ServiceID );
    if ($service) {
        $serviceName = $service->service_name;
    }

    my $versionNum = $file->VersionNum();

    my $subject = "New Orchard Sales File Error for $clientName";
    if ($serviceName) {
        $subject .= ": $serviceName v$versionNum";
    } elsif ( $file->Notes ) {
        $subject .= ' (' . $file->Notes . ')';
    }

    my $to   = 'filebot@royaltyshare.com';
    my $from = 'fileissues@royaltyshare.com';

    my $clientURL = "https://" . Common::RSApp::GetClientVHost() . ".royaltyshare.com";
    my $fileName  = $file->OrigFileName();

    my $flattery = Common::Flattery::FlatteryBot->acquireFlattery( flatteryAmount => 1 );

    my $body = "A recent Orchard sales file automatically uploaded to a customer site has encountered an error.

File name: $fileName

Customer website: $clientURL

This importer error will need to be researched and a new case opened to correct the issue,
similar to any other importer case.  Please open the new case as a standard RPS importer case,
or if the issue has already been reported, simply link the related case here.

Once the case is resolved please delete the file from the tracker page but do not upload the
file again.  The file will be automatically ingested the next time the fetcher runs, and the
customer will be notified of its success.

And remember, FlatteryBot says: $flattery";

    Common::Email->SendAWS(
        to      => $to,
        from    => $from,
        subject => $subject,
        body    => $body
    );
}    # _onInvalidOrchardNotifySupport

sub usage {
    my $err = shift;

    print STDERR <<EofUSAGE;
ERROR: $err
Usage: import_sales_file.pl CLIENT_ID FILE_ID [SERVICE_ID VERSION_NUM ALT_FILE_PATH]
EofUSAGE

    return 1;
}
