package BookPub::RDAS::Request::SalesData::Amazon;

use WWW::Mechanize;
use Data::Dumper;

use lib '/app/tools/common/lib';
use Common::Assert;
use Common::Exception;
use Common::DB::Item::SaleFeedServiceURL;

use lib '/app/tools/rdas/lib';
use RDAS::Fetcher::Mechanize::Authenticated;

use lib '/app/tools/bookpub/lib';
use BookPub::ServiceCredential;
use BookPub::Sale::Feed::SaleFeedService;
use BookPub::RDAS::Parser::SaleData::Amazon::Home;
use BookPub::RDAS::Parser::SaleData::Amazon::Download;
use BookPub::RDAS::Response::SalesData::Amazon;

use base 'BookPub::RDAS::Request::SalesData';

use constant kReportGenerationTimeout => '300';
use constant kSleepTime               => '5';

sub serviceID { return BookPub::Tracker::Service::AMAZON() }

sub _getResponseObject {
    my $self = shift;

    return new BookPub::RDAS::Response::SalesData::Amazon( report => $self->report, saleFeedFileID => $self->saleFeedFileID, @_ );
}

sub _init {

    # Disable host name verification because B&N certificate isn't
    $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;

    return shift->SUPER::_init(@_);
}

sub fetch {
    my $self = shift;
    $self->{_error} = undef;

    Log->info("************************************");
    Log->info("****  Begin sale file download  ****");
    Log->info("************************************");

    my $url = $self->_fetchFile() if ( $self->_login() );

    return $self->_storeContent($url) if $url;
}

sub parsers { shift->{_parsers} }

sub _credentials {
    my $self = shift;

    my $saleFeedFile = new BookPub::Sale::Feed::SaleFeedFile( saleFeedFileID => $self->saleFeedFileID );
    my $saleFeed = new BookPub::Sale::Feed::SaleFeed( saleFeedID => $saleFeedFile->SaleFeedID );

    unless ( $self->{_credentials} ) {
        my $cred = new BookPub::Sale::Feed::SaleFeedService( saleFeedServiceID => $saleFeed->SaleFeedServiceID );
        if ( $cred && $cred->Username && $cred->Password ) {
            $self->{_credentials} = [ $cred->Username, $cred->Password ];
        }
    }

    if ( $self->{_credentials} ) {
        return @{ $self->{_credentials} };
    } else {
        die "No login credentials";
    }
}

sub _baseURL {
    my $self = shift;

    my $saleFeedFile = BookPub::DB::Item::SaleFeedFile->Lookup( sale_feed_file_id => $self->saleFeedFileID );
    my $saleFeed = BookPub::DB::Item::SaleFeed->Lookup( sale_feed_id => $saleFeedFile->sale_feed_id );
    my $saleFeedService = BookPub::DB::Item::SaleFeedService->Lookup( sale_feed_service_id => $saleFeed->sale_feed_service_id );

    unless ( $self->{_baseURL} ) {
        my $saleFeedURL = Common::DB::Item::SaleFeedServiceURL->Lookup(
            service_id   => $saleFeedService->service_id,
            country_code => $saleFeedService->country_code
        );
        if ( $saleFeedURL && $saleFeedURL->url ) {
            $self->{_baseURL} = $saleFeedURL->url;
        }
    }

    if ( $self->{_baseURL} ) {
        return $self->{_baseURL};
    } else {
        die "No URL found";
    }
}

sub _countryCode {
    my $self = shift;

    unless ( $self->{_countryCode} ) {
        my $saleFeedFile = BookPub::DB::Item::SaleFeedFile->Lookup( sale_feed_file_id => $self->saleFeedFileID );
        my $saleFeed = BookPub::DB::Item::SaleFeed->Lookup( sale_feed_id => $saleFeedFile->sale_feed_id );
        if ( $saleFeed && $saleFeed->name =~ /_(\w{2})$/ ) {
            $self->{_countryCode} = $1;
        } elsif ( $saleFeed && $saleFeed->name =~ /_(\w{2})_Adjustment$/ ) {
            $self->{_countryCode} = $1;
        } else {
            my $saleFeedService = BookPub::DB::Item::SaleFeedService->Lookup( sale_feed_service_id => $saleFeed->sale_feed_service_id );
            if ( $saleFeedService && $saleFeedService->country_code ) {
                $self->{_countryCode} = $saleFeedService->country_code;
            }
        }
    }

    if ( $self->{_countryCode} ) {
        return $self->{_countryCode};
    } else {
        die "No Country Code found";
    }
}

sub _login {
    $^W = 0;    # disable UTF8 warnings

    return 1 if ( RDAS::Fetcher::Mechanize::Authenticated::LoggedIn() );

    my $self = shift;
    my ( $uname, $passwd ) = $self->_credentials();
    my $url = $self->_baseURL() . "/gp/flex/sign-in";

    my $fetcher = $self->_fetchPage($url) || return;

    # Use the underlying Mechanize object to submit the login form.
    #
    my $_mech  = $fetcher->_getMechObject();
    my $result = $_mech->submit_form(
        form_number => 0,
        fields      => {
            username => $uname,
            password => $passwd,
        }
    );

    my $parser = new BookPub::RDAS::Parser::SaleData::Amazon::Home( content => $fetcher->content() );

    if ( $parser->InEnglish ) {
        Log->info(" Using In English link ");
        $fetcher = $self->_fetchPage( $parser->InEnglish );
        $parser = new BookPub::RDAS::Parser::SaleData::Amazon::Home( content => $fetcher->content() );
    } elsif ( $parser->InEnglishBR ) {
        Log->info(" Using In English link ");
        $fetcher = $self->_fetchPage( $parser->InEnglishBR );
        $parser = new BookPub::RDAS::Parser::SaleData::Amazon::Home( content => $fetcher->content() );
    } else {
        Log->info(" Using default link ");
        $fetcher = $self->_fetchPage("/");
        $parser = new BookPub::RDAS::Parser::SaleData::Amazon::Home( content => $fetcher->content() );
    }

    if ( $parser->Logout ) {
        Log->info(" ++ Login successful ++");
    } elsif ( $parser->Interstitial ) {
        Log->info(" ++ Login successful ++");
    } elsif ( $parser->UpdatePrompt ) {
        Log->info(" ++ Login successful ++");
    } elsif ( $parser->Welcome ) {
        Log->info(" ++ Login successful ++");
    } else {
        Log->error("BookPub::RDAS::Request::SaleData::Amazon - Authentication failed ");
        return;
    }

    return RDAS::Fetcher::Mechanize::Authenticated::LoggedIn(1);
}

sub _fetchFile {
    my $self      = shift;
    my $startDate = new Common::Date( $self->SaleFeedFile->StartDate );
    my $endDate   = new Common::Date( $self->SaleFeedFile->EndDate );

    my $url;
    my $start = localtime;

    Log->info(" Request start time: $start");

    my $totalSleep = 0;

    while ( !$url && $start + kReportGenerationTimeout > $totalSleep ) {
        if ( $url = $self->_getReportURL() ) {
            Log->info(" -- Report URL: $url");
        } else {
            Log->info( "  - Report not generated, sleeping " . kSleepTime . " seconds" );
            Log->info( "  - I've been sleeping for " . $totalSleep . " seconds so far." );
            $totalSleep += kSleepTime;
            sleep kSleepTime;
        }
    }

    die "Report generation wait time exceeded (timeout)"
      unless ($url);

    return $url;
}

sub _getReportURL {
    my $self = shift;

    Log->info(" Fetching report generation page");

    die Common::Exception->new( "No URL stored for file " . $self->SaleFeedFile->Filename() )
      unless ( $self->SaleFeedFile->URL );

    my $fetcher = $self->_fetchPage( $self->_baseURL() . $self->SaleFeedFile->URL() ) || die;

    my $parser = new BookPub::RDAS::Parser::SaleData::Amazon::Download( content => $fetcher->content() ) || return;

    if ( $parser->Error() && $parser->Error =~ /error/ ) {
        Log->debug( $fetcher->content() );
        die "Failed to download sale file: " . $parser->Error();
    }

    return $parser->Link();
}

sub _storeContent {
    my $self = shift;
    my $url  = shift;
    Log->info(" + Fetch report");

    my $fetcher = $self->_fetchPage($url) || return;
    my $content = $fetcher->content();

    my $filename = $fetcher->mechanize()->response()->filename();

    if ( $filename =~ /^(\w{5}_)(.+)$/ ) {
        $filename = $1 . $self->_countryCode() . "_" . $2;
    }

    if ( $self->SaleFeedFile->SaleFeedID ) {
        my $feed = BookPub::DB::Item::SaleFeed->Lookup( sale_feed_id => $self->SaleFeedFile->SaleFeedID );
        if ( $feed->allow_dupes eq 'Y' ) {
            my $dupe = BookPub::DB::Item::File->Lookup( orig_file_name => $filename );

            if ( $dupe && $filename =~ /^(.+)(\.xls)$/ ) {
                $filename = $1 . "_(1)" . $2;
            }
        }
    }

    Log->info( "Filename: " . $filename );

    if ( $filename =~ /.xls/ ) {
        $self->SaleFeedFile->Filename($filename);
        $self->SaleFeedFile->save();
        return $self->{_report} = $content;
    }

    return;
}

1;
