package BookPub::RDAS::Request::SaleFeedFileList::Amazon;

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

use lib '/app/tools/common/lib';
use Common::Assert;
use Common::Date;
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::FileList;
use BookPub::DB::Item::SaleFeed;

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

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

sub reportFrequency { 'monthly' }

sub _validOptions {
    return ( shift->SUPER::_validOptions, 'reports', 'reportDate' );
}

sub _init {
    my $self = shift->SUPER::_init(@_);

    Log->debug( Dumper \@_ );
    assert( $self->saleFeedServiceID );

    $self->{_service} = new BookPub::Sale::Feed::SaleFeedService( saleFeedServiceID => $self->saleFeedServiceID );
    $self->{_feed} = new BookPub::Sale::Feed::SaleFeed( saleFeedID => $self->saleFeedID ) if ( $self->saleFeedID );

    die "Unable to find service credentials." unless ( $self->service );

    return $self;
}

sub service { shift->{_service} }
sub parsers { shift->{_parsers} }
sub files   { shift->{_files} }
sub feed    { shift->{_feed} }

sub Files {
    my $self = shift;

    unless ( $self->files ) {
        $self->fetch();
    }

    return $self->files;
}

sub Feeds {
    my $self = shift;

    my $files = $self->Files();

    my %feeds;

    foreach my $file (@$files) {
        if ( $file->{filename} =~ /^(\w{5})/ ) {
            my $name = $1;

            $name .= "_Adjustment" if ( $file->{filename} =~ /Adjust/ );

            if ( $file->{countryCode} ) {
                $name .= "_" . $file->{countryCode};
            }

            $feeds{$name} = 1;
        }
    }

    my @feeds;

    foreach my $feed ( keys %feeds ) {
        push( @feeds, { name => $feed, feed => $feed } );
    }

    return \@feeds;
}

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

    return $self->_fetchFileList() if ( $self->_login() );
}

sub _credentials {
    my $self = shift;

    unless ( $self->{_credentials} ) {
        my $cred = new BookPub::Sale::Feed::SaleFeedService( saleFeedServiceID => $self->service->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 _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->notice(" Using In English link ");
        $fetcher = $self->_fetchPage( $parser->InEnglish );
        $parser = new BookPub::RDAS::Parser::SaleData::Amazon::Home( content => $fetcher->content() );
    } elsif ( $parser->InEnglishBR ) {
        Log->notice(" Using In English link ");
        $fetcher = $self->_fetchPage( $parser->InEnglishBR );
        $parser = new BookPub::RDAS::Parser::SaleData::Amazon::Home( content => $fetcher->content() );
    } else {
        Log->notice(" Using default link ");
        $fetcher = $self->_fetchPage("/");
        $parser = new BookPub::RDAS::Parser::SaleData::Amazon::Home( content => $fetcher->content() );

        # if we came in through this path, we may still need to request the English version of the pages.
        # also, it doesn't appear the Brazil site is any different now, so we don't need to treat that
        # special (even though we left in the old check above [for now])
        if ( $parser->InEnglish ) {
            Log->notice(" Using In English link ");
            $fetcher = $self->_fetchPage( $parser->InEnglish );
            $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::SaleFeedFileList::Amazon - Authentication failed");
        return;
    }

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

sub _fetchFileList {

    my $self = shift;
    my $saleFeedID = $self->feed->SaleFeedID if ( $self->feed );
    my $startDate;

    if ( $self->feed ) {
        $startDate = new Common::Date( $self->feed->DownloadStartDate() );
    } else {
        $startDate = new Common::Date( $self->service->DownloadStartDate() );
    }

    assert($startDate);

    my $url = $self->_baseURL() . "/gp/vendor/members/digital-media/reports?ref_=vc_ven-digital-media-reports_subNav";

    Log->info(" + Fetch file list page");

    while ($url) {

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

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

        if ( $parser->Error() ) {
            Log->error( "Fetch failed: " . $parser->Error() );
            return;
        }

        my $files = $parser->Files();

        if ($files) {
            $self->{_files} = [] unless ( $self->files );

            foreach my $file (@$files) {

                # Limit results to a specific feed if we specified a feed.
                if ( $self->_isFeedMatch( $file->{filename} ) ) {

                    my $feedStartDate = $startDate;

                    my $feed;
                    if ( $self->feed ) {
                        $feed = $self->feed;
                    } else {
                        my $feedName = ( split /_-/, $file->{filename} )[0];
                        my $feedDBItem =
                          BookPub::DB::Item::SaleFeed->Lookup( sale_feed_service_id => $self->saleFeedServiceID, name => $feedName );
                        $feed = BookPub::Sale::Feed::SaleFeed->new( dbItem => $feedDBItem );
                    }

                    if ( $feed && $feed->AllowDupes eq 'Y' ) {
                        $feedStartDate = new Common::Date( $feed->StartDate );
                    }

                    if ( $feedStartDate <= new Common::Date( $file->{end} ) ) {
                        Log->debug(" -- adding $file->{filename}. Date $feedStartDate <= $file->{end}");
                        push( @{ $self->{_files} }, $file );
                    } else {
                        Log->debug(" -- ignore $file->{filename}. Date $feedStartDate < $file->{end}");
                    }
                }
            }
        }

        $url = undef;

    }

    return $self->files;
}

sub _isFeedMatch {
    my $self = shift;
    my $filename = shift || die;

    my $feedName = $self->feed->Name() if ( $self->feed );

    my $name;
    my $adjustment;

    if ($feedName) {
        if ( $feedName =~ /^(\w+)_(Adjustment)/ ) {
            $name       = $1;
            $adjustment = $2;
        } else {
            $name = $feedName;
        }
    }

    #($name, $adjustment) = split( /_/, $feedName ) if( $feedName );

    Log->debug(" **** No feed name, assume match") unless ($feedName);

    return 1 unless ($feedName);

    Log->debug(" **** Checking for feed match. F: $feedName, N: $name, File: $filename");

    if ( $filename =~ /^$name/ ) {
        if ( $adjustment && $filename =~ /Adjust/ ) {
            Log->debug("  **** match! **** ");
            return 1;
        } elsif ( !$adjustment && $filename !~ /Adjust/ ) {
            Log->debug("  **** match! **** ");
            return 1;
        }
    }

    Log->debug("  **** No match **** ");
    return;
}

sub _baseURL {
    my $self = shift;

    my $saleFeedService = BookPub::DB::Item::SaleFeedService->Lookup( sale_feed_service_id => $self->saleFeedServiceID );

    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";
    }
}

1;
