#---------------------------------------------------------------
# ____                   _ _         ____  _
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/
#
# Copyright (C) 2010 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#---------------------------------------------------------------
package BookPub::Sale::Report::Royalty::SalesFileValidator;
use strict;
use warnings;
use Data::Dumper;

# This package provides a 'Factory' interface for the Royalty Report sales file validation.
# We want to check for things that could cause an output file to fail and catch them early.
# It will return the 'correct' class, based on client id, if we have set up validation for that client.

use lib '/app/tools/common/lib';
use Common::RSApp;
use Common::Assert;
use Common::Email;
use Common::Flattery::FlatteryBot;

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

use lib '/app/tools/bookpub/lib';
use BookPub::DB::Item::File;
use BookPub::DB::Item::Service;

use BookPub::Sale::Report::Royalty::BerrettKoehler;
use BookPub::Sale::Report::Royalty::HachetteUK;
use BookPub::Sale::Report::Royalty::Macmillan;
use BookPub::Sale::Report::Royalty::MacmillanAU;
use BookPub::Sale::Report::Royalty::MacmillanUK;
use BookPub::Sale::Report::Royalty::RowmanLittlefield;
use BookPub::Sale::Report::Royalty::SagePub;
use BookPub::Sale::Report::Royalty::Wiley;

my %gPackages = (
    Client::Client::kBerrettKoehler()    => 'BookPub::Sale::Report::Royalty::BerrettKoehler',
    Client::Client::kHachetteUK()        => 'BookPub::Sale::Report::Royalty::HachetteUK',
    Client::Client::kMacmillan()         => 'BookPub::Sale::Report::Royalty::Macmillan',
    Client::Client::kMacmillanAU()       => 'BookPub::Sale::Report::Royalty::MacmillanAU',
    Client::Client::kMacmillanAUPrint()  => 'BookPub::Sale::Report::Royalty::MacmillanAU',
    Client::Client::kMacmillanUK()       => 'BookPub::Sale::Report::Royalty::MacmillanUK',
    Client::Client::kRowmanLittlefield() => 'BookPub::Sale::Report::Royalty::RowmanLittlefield',
    Client::Client::kSagePub()           => 'BookPub::Sale::Report::Royalty::SagePub',
    Client::Client::kWiley()             => 'BookPub::Sale::Report::Royalty::Wiley',
);

sub Validate {
    my ($fileID) = @_;
    assert( defined $fileID, 'MISSING fileID parameter' );

    # Do we have validation set up for this client?
    #
    my $report;
    my $clientID = Common::RSApp::GetClientID();
    my $pkg      = $gPackages{$clientID};

    # By default, we'll consider the file valid.
    # That way we don't break anything for clients who don't need/have this validation in place.
    my $isValid = 1;

    if ($pkg) {
        Common::Log::Print("Validating File...");

        my %validation = $pkg->validateFile($fileID);

        $isValid = $validation{isValid};

        # If we didn't pass validation, we need to send out an email.
        # The import sales script will take care of putting the file on hold.
        if ( !$isValid ) {
            Common::Log::Print("File did not pass validation");
            _sendOnHoldEmail( $clientID, $fileID, %validation );
        }
    }

    return $isValid;
}

sub _sendOnHoldEmail {
    my ( $clientID, $fileID, %validation ) = @_;

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

    my $file = BookPub::DB::Item::File->Lookup( file_id => $fileID );
    my $fileName = $file->orig_file_name;

    # Service is the one thing that is always part of the SAN criteria, so we'll add that now.
    my $serviceName;
    my $service = BookPub::DB::Item::Service->Lookup( service_id => $file->service_id );
    if ($service) {
        $serviceName = $service->service_name;
    }

    my $versionNum = $file->version_num;

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

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

    my $trackerURL = "https://" . Common::RSApp::GetClientVHost() . ".royaltyshare.com/bookpub/tracker";
    my $flattery = Common::Flattery::FlatteryBot->acquireFlattery( flatteryAmount => 1 );

    my $errorMessaging;

    # First we'll list all of the missing attributes.
    my $i = 1;
    foreach my $attribute ( sort keys %validation ) {

        # We'll deal with SAN and MultipleSANs separately
        if ( $validation{$attribute} && uc($attribute) ne 'SAN' && $attribute ne 'MultipleSANs' ) {
            if ( $i == 1 ) {
                $errorMessaging = "\nThe following file attributes are missing or cannot be detected:\n";
            }
            $errorMessaging .= $i . ". " . $attribute;

            # Some clients provide more details than just 'missing'.
            # We'll include some of those in the email.
            if ( $validation{$attribute} eq 'invalid' ) {
                $errorMessaging .= " (invalid) ";
            }

            $errorMessaging .= "\n";
            $i++;
        }
    }

    # If we listed any attribute errors, we need to add the instructions for those now.
    if ( $i > 1 ) {
        $errorMessaging .=
"\nPlease review the file and update this case with the location of the missing attribute or how the attribute should be derived.  List the attributes in order, followed by the location/derivation information, and assign to the appropriate contact.\n";
    }

    # And now we'll list the criteria for the missing SAN (for clients who assign SANs at the file level)
    # Unless we don't have any criteria for the SAN, in which case we have canned response ready.
    if (   ( $validation{'SAN'} && $validation{'SAN'} eq "NONE" )
        || ( $validation{'MultipleSANs'} && $validation{'MultipleSANs'} eq "NONE" ) ) {
        $errorMessaging .= "\nNo SAN criteria is set up for this service.\n";
    } else {
        if ( $validation{'SAN'} ) {
            $errorMessaging .= "\nNo SAN detected for the following criteria:\n";
            $errorMessaging .= "1. Service: $serviceName\n";

            my $sanCriteria = $validation{'SAN'};

            $i = 2;
            foreach my $criteria ( sort keys %$sanCriteria ) {

                # We automatically add Service above, so there's no need to add it again.
                if ( $criteria ne "Service" ) {
                    $errorMessaging .= $i . ". " . $criteria . ": " . $sanCriteria->{$criteria} . "\n";
                    $i++;
                }
            }
        }

        # For clients who assign SANs at the sale level, we may have a few of these blocks to loops through.
        if ( $validation{'MultipleSANs'} ) {
            my $multipleSANs = $validation{'MultipleSANs'};

            foreach my $criteriaBlock ( sort keys %$multipleSANs ) {
                my $sanCriteria = $multipleSANs->{$criteriaBlock};

                $errorMessaging .= "\nNo SAN detected for the following criteria:\n";
                $errorMessaging .= "1. Service: $serviceName\n";

                $i = 2;
                foreach my $criteria ( sort keys %$sanCriteria ) {
                    if ( $criteria ne "Service" ) {
                        $errorMessaging .= $i . ". " . $criteria . ": " . $sanCriteria->{$criteria} . "\n";
                        $i++;
                    }
                }
            }
        }

        if ( $validation{'SAN'} || $validation{'MultipleSANs'} ) {
            $errorMessaging .=
"\nPlease contact the customer for the missing SAN number for each set of criteria listed.  Provide the missing SAN, in order, and assign the case to the appropriate contact.\n";
        }
    }

    my $body = "We are missing one or more sales file attributes for the following file: $fileName

The file is uploaded here on the customer tracker page: $trackerURL
$errorMessaging
For more information about file attributes and SAN assignment by customer, please see the PRD for Automated Sales Attribute Check found here:  https://royaltyshare.fogbugz.com/default.asp?W216

And remember, FlatteryBot says: $flattery";

    # Let's only send these out in production because a case will be created in FogBugz.
    if ( Common::RSApp::IsProductionServer() ) {
        Common::Email->SendAWS(
            to      => $to,
            from    => $from,
            subject => $subject,
            body    => $body
        );
    } else {
        print STDERR $body . "\n";
    }
}

1;
