package BookPub::RDAS::Request::ProductPrice::Amazon;

use lib '/app/tools/bookpub/lib';
use base 'BookPub::RDAS::Request::ProductPrice';

use Common::Assert;

use BookPub::RDAS::Parser::ProductPrice::Amazon;
use BookPub::RDAS::URL::ProductPrice::Amazon;
use BookPub::RDAS::Response::ProductPrice::Amazon;
use BookPub::Catalog::Product::Book;
use BookPub::Catalog::Book::Title;
use BookPub::Catalog::Author;

sub includePhysicalProducts { 1 }

sub _getParserObject {
    my $self = shift;
    return new BookPub::RDAS::Parser::ProductPrice::Amazon(@_);
}

sub _getURLObject {
    my $self = shift;
    return new BookPub::RDAS::URL::ProductPrice::Amazon( bookID => $self->bookID(), productID => $self->productID(), @_ );
}

sub _getResponseObject {
    my $self = shift;
    return new BookPub::RDAS::Response::ProductPrice::Amazon( parser => $self->parser, productID => $self->productID, @_ );
}

# Updated the run process to retry if we have attempted to fetch using a cached URL.
# Initially this is only don't with Amazon because we are seeing most fetching problems
# with them due to name based searches.
#
# I'm assuming we want to move this logic up one level so it works for all Product Monitor
# Price requests.
sub fetch {
    my $self = shift;
    my %args = @_;

    return $self->SUPER::fetch(%args) if ( $self->nosave() );

    my $storedFetch = $self->_fetchFromStoredURL();
    my $searchedFetch = $self->_fetchFromSearchedURL() unless ( $storedFetch && $storedFetch->success && $self->_validatePage() );

    my $fetch = $searchedFetch ? $searchedFetch : $storedFetch;

    if ( $fetch->success ) {
        return 1;
    } else {
        $self->fail( code => $fetch->errorCode );
        return;
    }
}

sub _fetchFromStoredURL {
    my $self = shift;
    Log->notice("Fetching using stored URL");

    my $urlObject = $self->_getURLObject();
    my $url       = $urlObject->storedURL();

    if ($url) {
        $self->{_storedURL} = $url;

        my $fetcher = $self->_getFetchObject($url);
        $self->{_content} = $fetcher->content();

        return $fetcher;
    }

    return;
}

sub _fetchFromSearchedURL {
    my $self = shift;

    Log->notice("Fetching using searched URL");

    my $urlObject = $self->_getURLObject();
    $url = $urlObject->GetURL( bookID => $self->bookID, productID => $self->productID );

    if ( $self->{_storedURL} && $self->{_storedURL} eq $url ) {
        Log->notice("Not fetching again because the stored URL == searched URL");
        return;
    }

    my $fetcher = $self->_getFetchObject($url);
    $self->{_content} = $fetcher->content();

    return $fetcher;
}

sub _validatePage {
    my $self = shift;

    return unless ( $self->content() );
    $self->parse();

    if ( $self->_validateTitleMatch() && $self->_validateAuthorMatch() ) {
        Log->info(" ++ Validation successful");
        return 1;
    } else {

        # We failed page validation so we need to invalidated all product monitor
        # items and the current stored URL.
        $self->_invalidateStoredURL();
    }

    return;
}

sub _invalidateStoredURL {
    my $self = shift;

    my $urlObj = $self->_getURLObject();
    $urlObj->invalidate;
}

sub _validateTitleMatch {
    my $self    = shift;
    my %args    = @_;
    my $product = new BookPub::Catalog::Product::Book( productID => $self->productID() );
    assert($product);

    my $hasSubtitle = $self->parser->can('Subtitle');

    my $book = new BookPub::Catalog::Book( bookID => $product->BookID );

    my $fetchedTitle = $self->parser->Title;
    my $fetchedSubtitle = $self->parser->Subtitle if ($hasSubtitle);

    my $catalogTitle = $book->Title;
    my $catalogSubtitle = $book->Subtitle if ($hasSubtitle);

    Log->info("   Validate fetched title matches catalog title");

    if ( !defined($fetchedTitle) ) {
        Log->info("   -- Undetermined title from request object");
        return;
    }

    if ( !defined($catalogTitle) ) {
        Log->info("   -- Undetermined title from catalog");
        return;
    }

    my $fetched = new BookPub::Catalog::Book::Title( title => $fetchedTitle, subtitle => $fetchedSubtitle );
    my $catalog = new BookPub::Catalog::Book::Title( title => $catalogTitle, subtitle => $catalogSubtitle );
    my $parsed  = new BookPub::Catalog::Book::Title( parse => $fetchedTitle );

    #die $parsed->Title . " eq " . $catalog->Title;
    unless ( $fetched->fuzzyMatch( title => $catalog->Title, subtitle => $catalog->Subtitle )
        || $parsed->fuzzyMatch( title => $catalog->Title, subtitle => $catalog->Subtitle )
        || $parsed->titleFuzzyMatch( title => $catalog->Title )
        || $fetched->contains( title => $catalog->Title, subtitle => $catalog->Subtitle ) ) {
        Log->info( "   -- Title match failed. Fetched: \"" . $fetched->Combined . "\" Catalog: \"" . $catalog->Combined . "\"" );
        return;
    }

    Log->info("   -- Title match success!");
    return 1;
}

sub _validateAuthorMatch {
    my $self    = shift;
    my %args    = @_;
    my $product = new BookPub::Catalog::Product::Book( productID => $self->productID() );

    assert($product);

    my $book = new BookPub::Catalog::Book::WithAuthor( bookID => $product->BookID );

    Log->info("   Validate fetched author matches catalog author");

    my $fetched = new BookPub::Catalog::Author( $self->parser->Author );
    my $catalog = new BookPub::Catalog::Author( $book->AuthorName );

    if ( !defined( $fetched->Author ) ) {
        Log->info("   -- Undetermined author from request object");
        return;
    }

    if ( !defined( $catalog->Author ) ) {
        Log->info("   -- Undetermined author from catalog");
        return;
    }

    unless ( $fetched->fuzzyMatch( $catalog->Author ) ) {
        Log->info( "   -- Author match failed. Fetched: \"" . $fetched->Author . "\" Catalog: \"" . $catalog->Author . "\"" );
        return;
    }

    Log->info( "Fetched Author: " . $fetched );
    Log->info( "Catalog Author: " . $fetched );

    Log->info("   -- Author match success!");
    return 1;
}

1;
