#---------------------------------------------------------------
# ____                   _ _         ____  _
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/
#
# Copyright (C) 2011 RoyaltyShare, Inc.   All Rights Reserved
#---------------------------------------------------------------
package BookPub::Sale::Feed::SaleFeedFile;

use strict;
use warnings;

use Carp;
use Data::Dumper;

use lib '/app/tools/common/lib';
use lib '/app/tools/bookpub/lib';

use BookPub::RDAS::Request::SalesData;
use BookPub::DB::Item::SaleFeedService;
use BookPub::DB::Item::SaleFeed;
use Common::RSApp;
use Common::Util;
use Common::Assert;
use Common::FormObject;
use Common::Email;

use base 'Common::FormObject';

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

    $self->SUPER::_init(%args);

    my %properties;
    if ( $args{dbItem} ) {
        $self->_propertiesFromDBItem( \%properties, $args{dbItem} );
    } elsif ( $args{serviceID} || $args{filename} ) {
        $self->_propertiesFromName( \%properties, %args );
    } elsif ( $args{saleFeedID} || $args{startDate} ) {
        $self->_propertiesFromStartDate( \%properties, %args );
    } elsif ( $args{saleFeedFileID} ) {
        $self->_propertiesFromDB( \%properties, %args );
    } else {
        $self->_propertiesFromDefaults( \%properties );
    }

    $self->_initProperties( \%properties );

    return $self;
}

sub _propertiesFromName {
    my ( $self, $hrProperties, %args ) = @_;
    my $name       = $args{filename};
    my $id         = $args{saleFeedServiceID};
    my $url        = $args{url};
    my $saleFeedID = $args{saleFeedID};
    my $start      = $args{startDate};
    my $end        = $args{endDate};

    assert( $name && $id );

    my $dbItem = BookPub::DB::Item::SaleFeedFile->LookupByName( filename => $name, sale_feed_service_id => $id );

    $hrProperties->{url} = $url;

    if ($dbItem) {
        $self->_propertiesFromDBItem( $hrProperties, $dbItem );
    } else {
        $self->_propertiesFromDefaults(
            $hrProperties,
            filename     => $name,
            service_id   => $id,
            start_date   => $start,
            end_date     => $end,
            url          => $url,
            sale_feed_id => $saleFeedID
        );
    }
}

sub _propertiesFromStartDate {
    my ( $self, $hrProperties, %args ) = @_;
    my $startDate  = $args{startDate};
    my $endDate    = $args{endDate};
    my $saleFeedID = $args{saleFeedID};

    Log->debug("_propertiesFromStartDate");
    assert( $startDate && $saleFeedID );

    my $dbItem = BookPub::DB::Item::SaleFeedFile->LookupByStartDate( start_date => $startDate, sale_feed_id => $saleFeedID );

    if ($dbItem) {
        $self->_propertiesFromDBItem( $hrProperties, $dbItem );
    } else {
        $self->_propertiesFromDefaults(
            $hrProperties,
            start_date   => $startDate,
            end_date     => $endDate,
            sale_feed_id => $saleFeedID
        );
    }
}

sub _propertiesFromDB {
    my ( $self, $hrProperties, %args ) = @_;
    my $id = $args{saleFeedFileID};

    Log->debug("_propertiesFromDB");
    my $dbItem = BookPub::DB::Item::SaleFeedFile->Lookup( sale_feed_file_id => $id );

    $hrProperties->{url} = $args{url};

    $self->_propertiesFromDBItem( $hrProperties, $dbItem );
}

sub _propertiesFromDBItem {
    my ( $self, $hrProperties, $dbItem ) = @_;

    return unless ($dbItem);

    $hrProperties->{sale_feed_file_id} = $dbItem->sale_feed_file_id;
    $hrProperties->{sale_feed_id}      = $dbItem->sale_feed_id;
    $hrProperties->{filename}          = $dbItem->filename;
    $hrProperties->{path}              = $dbItem->path;
    $hrProperties->{url}               = $dbItem->url;
    $hrProperties->{status}            = $dbItem->status;
    $hrProperties->{start_date}        = $dbItem->start_date;
    $hrProperties->{end_date}          = $dbItem->end_date;
    $hrProperties->{date_created}      = $dbItem->date_created;
}

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

    Log->debug("_propertiesFromDefault");

    $hrProperties->{sale_feed_id} = $args{sale_feed_id};
    $hrProperties->{filename}     = $args{filename};
    $hrProperties->{status}       = 'pending';
    $hrProperties->{start_date}   = $args{start_date};
    $hrProperties->{end_date}     = $args{end_date};
    $hrProperties->{url}          = $args{url};
}

sub _initProperties {
    my ( $self, $props ) = @_;

    $self->{SaleFeedFileID} = $props->{sale_feed_file_id};
    $self->{SaleFeedID}     = $props->{sale_feed_id};
    $self->{Filename}       = $props->{filename};
    $self->{Path}           = $props->{path};
    $self->{Status}         = $props->{status};
    $self->{URL}            = $props->{url};
    $self->{StartDate}      = $props->{start_date};
    $self->{EndDate}        = $props->{end_date};
    $self->{DateCreated}    = $props->{date_created};
}

sub download {
    my $self = shift;

    my $saleFeed = new BookPub::Sale::Feed::SaleFeed( saleFeedID => $self->SaleFeedID );
    my $service = new BookPub::Sale::Feed::SaleFeedService( saleFeedServiceID => $saleFeed->SaleFeedServiceID );

    unless ( $self->Status =~ '(pending|missing)' ) {
        Log->notice( "Not downloading " . $self->Filename . " with status '" . $self->Status . "'" );
        return;
    }

    Log->notice( "Starting download process for " . $self->Filename );

    if ( $self->Filename && $saleFeed->AllowDupes eq 'N' ) {
        return if ( $self->_duplicateFound() );
    }

    # Save the file to the database if we haven't already
    $self->save();

    my $request = BookPub::RDAS::Request::SalesData->GetRequestObject( $service->ServiceID, saleFeedFileID => $self->SaleFeedFileID );
    eval { die "Failed to fetch file.\n" unless ( $request->run() ); };

    my $error = $@ if ($@);

    if ($error) {
        Log->error("Download failure: $error");

        if ( $self->Filename ) {
            my $client = new Common::Client( clientID => Common::RSApp::GetClientID() );
            my $name = $client->ClientName || "Client ID: " . Common::RSApp::GetClientID();

            my $reportEmail = Common::RSApp::GetConfig( 'bookpub', 'error_report_email' );
            my $body = "Sales file download failure.\n\n" . $self->Filename . "\n\n$error\n\n";

            Common::Email->SendAWS(
                to      => $reportEmail,
                from    => 'do-not-reply@royaltyshare.com',
                subject => "Sale File Fetch Error Detected ($name).",
                body    => $body
            );
        }
    }
}

# Check for duplicate files
sub _duplicateFound {
    my $self = shift;

    if (
        BookPub::DB::Item::SaleFeedFile->hasDuplicateDate(
            start_date   => $self->StartDate,
            end_date     => $self->EndDate,
            sale_feed_id => $self->SaleFeedID,
            filename     => $self->Filename
        )
      ) {

        Log->warn( "File with duplicate date range found when saving '" . $self->Filename . "'.  Ignoring this file!" );
        return 1;
    }

    return;
}

sub save {
    my $self = shift;

    my $dbitem;

    if ( $self->SaleFeedFileID ) {
        $dbitem = BookPub::DB::Item::SaleFeedFile->Lookup( sale_feed_file_id => $self->SaleFeedFileID );
    }

    unless ($dbitem) {
        $dbitem = BookPub::DB::Item::SaleFeedFile->Create();
    }

    $dbitem->filename( $self->Filename );
    $dbitem->status( $self->Status );
    $dbitem->url( $self->URL );
    $dbitem->sale_feed_id( $self->SaleFeedID );
    $dbitem->start_date( $self->StartDate );
    $dbitem->end_date( $self->EndDate );

    $dbitem->save;
    return $self->_init( dbItem => $dbitem );
}

sub updateStatus {
    my $self = shift;
    my $status = shift || die;

    $self->{Status} = $status;

    $self->save();
}

###
1;    #
###
