package BookPub::RDAS::Request::SaleFeedFileList::Apple;

use Data::Dumper;

use lib '/app/tools/common/lib';
use Common::Assert;
use Common::Date;
use Common::Country;

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

use lib '/app/tools/bookpub/lib';
use BookPub::RDAS::Parser::SaleData::Apple::Home;
use BookPub::RDAS::Parser::SaleData::Apple::Feed;
use BookPub::RDAS::Parser::SaleData::Apple::FileList;
use BookPub::RDAS::URL::ProductPrice::Apple;

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

use constant kMaxRetries => 3;

sub error { shift->{_error} }
sub files { shift->{_files} }

sub reportFrequency { 'monthly' }

sub Files {
    my $self = shift;
    my @results;

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

    return $self->files;
}

sub Feeds {
    my $self  = shift;
    my $files = $self->Files;

    my %feeds;
    my @results;

    foreach my $file ( @{$files} ) {
        next unless ( $file->{filename} );
        my ( $feed, $date, $country ) = split( /[_\.]/, $file->{filename} );
        die "Malformated filename: $file->{filename}" unless ( $feed && $country );

        my $key = $feed . "_" . $country;
        $feeds{$key} = { name => $key, feed => $key };
    }

    foreach my $feed ( keys %feeds ) {
        push( @results, $feeds{$feed} );
    }

    return \@results;
}

sub fetch {
    my $self = shift;

    # Disable warnings coming from HTTP::Cookie.
    $^W = 0;

    my $success = 0;
    $self->{_error} = undef;

    for ( my $retry = 1 ; $retry <= kMaxRetries && !$success && !$self->error() ; $retry++ ) {
        $self->{_parser} = {};

        unless ( $self->{_parser}->{home} = $self->loginRequired ? $self->_loginHomePage : $self->_fetchHomePage ) {
            Log->info( "Failed to fetch homepage.  Retry ( $retry of " . kMaxRetries . ")" );

            #die "Authentication failed" if( $retry > 1 );
            next;
        }

        if ( $self->_feedHome() ) {
            $self->{_parser}->{feedHome} = $self->_feedHome();

            $self->_fetchFileList();

            $success = 1;
        }
    }

    unless ($success) {
        $self->{_error} = "Service authentication failed for service" unless ( $self->error );
        Log->info( "ERROR: " . $self->error() ) if ( $self->error );

        #$self->fail( failure => $self->error );
    }

    return $success;
}

sub _credentials {
    my $self = shift;

    unless ( $self->{_credentials} ) {
        my $cred = new BookPub::Sale::Feed::SaleFeedService( saleFeedServiceID => $self->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 loginRequired { shift->{_loginRequired} }

sub _isLoginPage {
    my $self = shift;
    my $parser = shift || die;

    if ( $parser->Login ) {
        $self->{_loginRequired} = 1;
        Log->info("Not authenticated!");
        return 1;
    }

    $self->{_loginRequired} = undef;

    return;
}

sub _loginHomePage {
    my $self = shift;
    my ( $uname, $passwd ) = $self->_credentials();
    my $credentials = { theAccountName => $uname, theAccountPW => $passwd };

    Log->info(" + Login to homepage");

    assert( $uname,  "Username required" );
    assert( $passwd, "Password required" );

    return $self->_fetchHomePage($credentials);
}

sub _fetchHomePage {
    my $self        = shift;
    my $credentials = shift;

    Log->info(" + Fetch homepage");
    my $fetcher = $self->_fetchPage( BookPub::RDAS::URL::ProductPrice::Apple->SiteLoginURL(), form => $credentials ) || return;

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

    if ( $parser->Update && $parser->Continue ) {
        Log->warn("iTunes account alert seen.  Login to iTunes connect and clear the alert");

        $fetcher = $self->_fetchPage( BookPub::RDAS::URL::ProductPrice::Apple->SiteURL() . $parser->Continue ) || return;
        $parser = new BookPub::RDAS::Parser::SaleData::Apple::Home(
            content => $fetcher->content(),
            links   => $fetcher->links()
        );
    }

    return $self->_isLoginPage($parser) ? undef : $parser;
}

sub _fetchPage {
    my $self = shift;
    my $url  = shift;
    my %args = @_;

    my $fetcher = $self->_getFetchObject($url);

    if ( $fetcher->fetch(%args) ) {
        return $fetcher;
    } else {
        $self->{_error} = "Fetch failed.  HTTP Code: " . $fetcher->errorCode();
        return;
    }
}

sub _feedHome {
    my $self     = shift;
    my $parsers  = $self->parser;
    my $homepage = $parsers->{home};

    Log->info(" + Fetch feed home page");
    my $link = $homepage->link( text => 'Payments and Financial Reports' );

    if ($link) {
        $url = BookPub::RDAS::URL::ProductPrice::Apple->SiteURL . $link->url;

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

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

        return $self->_isLoginPage($parser) ? undef : $parser;
    }
    return;
}

sub _fetchFileList {
    my $self = shift;
    my @result;

    my $parsers = $self->parser;
    my $feeds   = $parsers->{feedHome};

    Log->info(" + Fetch feed Accounts");

    my $accounts = $feeds->Accounts()
      || [ {
            'feed'  => 'APPLE',
            'value' => '0',
            'name'  => 'Main Feed',
        }
      ];

    foreach my $account (@$accounts) {
        push( @result, $self->_fetchFileListByAccount( $account, $self->_startDate() ) );

        $parser->{home}      = $self->_fetchHomePage();
        $parsers->{feedHome} = $self->_feedHome();
    }

    $self->{_files} = \@result;
}

sub _fetchFileListByAccount {
    my $self      = shift;
    my $account   = shift || die "account required";
    my $startDate = shift || die "start date required";
    my %formArgs;

    my $parsers = $self->parser;
    my $feeds   = $parsers->{feedHome};

    my $url = BookPub::RDAS::URL::ProductPrice::Apple->SiteURL . $feeds->FormAction;

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

    Log->debug( "Account: " . Dumper $account );

    Log->debug( "Action: " . $feeds->FormAction );

    Log->debug( "Submit: " . $feeds->SubmitName );

    $formArgs{ $account->{select} } = $account->{value} if ( $account->{select} );
    $formArgs{ $feeds->SubmitName } = 'Earnings';

    my $fetcher = $self->_fetchPage($url);
    $fetcher->post( form => \%formArgs );

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

    return $self->_parseFiles( account => $account, parser => $parser, startDate => $startDate );
}

sub _parseFiles {
    my $self      = shift || return;
    my %args      = @_;
    my $account   = $args{account} || die "Account required";
    my $parser    = $args{parser} || return;
    my $startDate = $args{startDate} || return;

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

    my @files;

    die "Account feed not defined." unless ( $account->{feed} );

    foreach my $file (@$files) {
        next unless ( $file->{region} );
        next unless ( $file->{date} );

        my $country = Common::Country->Get( $file->{region} );
        my $code = $country ? $country->alpha2 : $file->{region};
        $code =~ s/\s/_/g;

        my $date = new Common::Date( $file->{date} );

        $file->{filename} = $account->{feed} . "_" . $date->asString("%m%y") . "_" . $code . ".txt";

        if ( $date < $startDate ) {
            Log->info("  --  Ignore file '$file->{filename}': date < $startDate");
        } else {
            my $feedName = $self->feed->Name() if ( $self->feed );

            my ( $name, $region ) = split( /_/, $feedName );

            # Limit results to a specific feed if we specified a feed.
            if ( !$feedName || $file->{filename} =~ /$name.*$region/ ) {
                Log->info(" Pushing file: $file->{filename}, Feed: $feedName");
                push( @files, $file );
            } else {
                Log->info(" Ignore $file->{filename}, Feed: $feedName");
            }
        }
    }

    return @files;
}

1;
