#---------------------------------------------------------------
# ____                   _ _         ____  _
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/
#
# Copyright (C) 2010 RoyaltyShare, Inc.   All Rights Reserved
#---------------------------------------------------------------
package BookPub::Catalog::Product::Book::WithProductMonitoring;

use strict;
use warnings;

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

use Common::RSApp;
use Common::Log;
use Common::Assert;
use Common::Client;
use Common::FormObject;

use BookPub::DB::Item::ProductMonitorAlert;
use BookPub::DB::Item::ProductMonitorItem;
use BookPub::DB::Item::ProductMonitorItemPrice;
use BookPub::DB::Item::ProductMonitorItemRank;
use BookPub::DB::Item::ProductServiceUrl;
use BookPub::DB::Item::BookProduct;
use BookPub::DB::Item::BestSellerBookProduct;
use BookPub::DB::Item::BestSellerList;
use BookPub::DB::Item::Service;
use BookPub::RDAS::Service;
use BookPub::RDAS::URL::ProductPrice;

use base 'BookPub::Catalog::Product::Book::WithPricing';

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

    # Invoke the inherited method first.
    #
    $self->SUPER::_initProperties($props);

    # If the product is not what we consider "published", we're going to suppress some of the data.
    #
    my $publishingStatus = $self->OnixCodePublishingStatus();
    my $published        = 0;

    if (   $publishingStatus eq BookPub::DB::Item::BookProduct::kStatusUnspecified
        || $publishingStatus eq BookPub::DB::Item::BookProduct::kStatusForthcoming
        || $publishingStatus eq BookPub::DB::Item::BookProduct::kStatusActive
        || !$publishingStatus ) {
        $published = 1;
    }

    # If this is an eBook, we will check for similar products.
    # Otherwise, we want to restrict everything to just this product.

    my @productIDs = $self->ProductID();

    if ( $published == 1 ) {
        if ( $self->ProductID() && BookPub::DB::Item::BookProduct->IsEBook( productID => $self->ProductID() ) ) {

            # JPK - Need to extend this to take the market id into account.  And probably the currency type.
            # Should be able to get that stuff out of the base class's items.
            #
            # Since I know the product_market_price_id of the primary price in the primary market (which we fetched
            # in the 'WithPricing' initProperties method), I think I'll just pass that info along.
            # The accessor ought to be able to back that up to find the right market_id, currency code, and price.
            #
            # There might not be a price yet.   It's possible.
            #
            my %additionalArgs;
            if ( $self->{DefaultPrimary} && $self->{DefaultPrimary}->MarketID() ) {
                my $marketID     = $self->{DefaultPrimary}->MarketID();
                my $currencyCode = $self->{DefaultPrimary}{Currency}{CurrencyCode};
                my $price        = $self->getCurrentPrice( $marketID, $currencyCode );

                $additionalArgs{marketID}     = $marketID;
                $additionalArgs{currencyCode} = $currencyCode;
                $additionalArgs{price}        = $price;
            }
            @productIDs = BookPub::DB::Item::BookProduct->GetProductIDsOfSimilarProducts( $self->ProductID(), %additionalArgs );
            $self->{CurrentPrices}{CurrentPrice} = $self->_getCurrentEbookPrices(@productIDs);
        } else {
            $self->{CurrentPrices}{CurrentPrice} = $self->_getCurrentPhysicalPrices(@productIDs);
        }

        $self->{ServiceRankings}{ServiceRanking} = $self->_getServiceRankings(@productIDs);
        $self->{NYTRankings}{NYTRanking}         = $self->_getNYTRankings(@productIDs);
    }

    my $lastMonitored = BookPub::DB::Item::ProductMonitorItem->GetLastMonitoredDate( product_id => \@productIDs, type => 'price' );
    $self->{PriceLastMonitored} = Common::FormObject::Scalar::DateTime->new( value => $lastMonitored );

    # !!! I am assuming we'll want this to use the same 'id grouping' logic we use for other product monitoring interfaces.
    #
    my $alertCount = BookPub::DB::Item::ProductMonitorAlert->CountActiveAlertsForProductIDs( \@productIDs );
    $self->{AlertCount} = $alertCount;

}

sub _getCurrentEbookPrices {
    my ( $self, @productIDs ) = @_;
    my @result;

    my @serviceIDs = BookPub::RDAS::Service->GetAllServiceIDs();

    foreach my $serviceID (@serviceIDs) {
        my $item = {};

        $item->{ServiceName} = $self->_getServiceName($serviceID);

        foreach my $productID (@productIDs) {
            my $currentPrice = BookPub::DB::Item::ProductMonitorItemPrice->GetCurrent( service_id => $serviceID, product_id => $productID );
            if ($currentPrice) {
                if ( $currentPrice->price ) {
                    $item->{Price} = Common::FormObject::Scalar::Money->new( value => $currentPrice->price );
                }

                my $product = BookPub::DB::Item::BookProduct->Lookup( product_id => $productID );

                my $urlObject = BookPub::RDAS::URL::ProductPrice->GetURLObject( $serviceID, bookID => $product->book_id );

                if ( $urlObject->url ) {
                    $item->{ServiceURL} = Common::FormObject::Scalar->new( value => $urlObject->url );

                    my $productMonitorItem =
                      BookPub::DB::Item::ProductMonitorItem->Lookup( product_monitor_item_id => $currentPrice->product_monitor_item_id );
                    $item->{LastVerified} = Common::FormObject::Scalar::Date->new( value => $productMonitorItem->last_verified );

                    my $bookFormat = BookPub::DB::Item::BookFormat->Lookup( book_format_id => $product->book_format_id );
                    if ( $bookFormat->book_format_subtype_id ) {
                        my $bookFormatSubtype =
                          BookPub::DB::Item::BookFormatSubtype->Lookup( book_format_subtype_id => $bookFormat->book_format_subtype_id );
                        if ($bookFormatSubtype) {
                            my $onixCode = BookPub::DB::Item::OnixCode->Lookup( onix_code_id => $bookFormatSubtype->onix_code_id );
                            if ($onixCode) {
                                $item->{eBookType} = Common::FormObject::Scalar->new( value => $onixCode->description );
                            }
                        }
                    }
                }
            }
        }

        push( @result, $item );
    }

    return \@result;
}

sub _getCurrentPhysicalPrices {
    my ( $self, $productID ) = @_;
    my @result;

    my @serviceIDs = BookPub::RDAS::Service->GetAllServiceIDs();

    foreach my $serviceID (@serviceIDs) {
        my $item = {};

        $item->{ServiceName} = $self->_getServiceName($serviceID);

        my $currentPrice = BookPub::DB::Item::ProductMonitorItemPrice->GetCurrent( service_id => $serviceID, product_id => $productID );
        if ($currentPrice) {
            if ( $currentPrice->price ) {
                $item->{Price} = Common::FormObject::Scalar::Money->new( value => $currentPrice->price );
            }

            my $product = BookPub::DB::Item::BookProduct->Lookup( product_id => $productID );

            my $urlObject = BookPub::RDAS::URL::ProductPrice->GetURLObject( $serviceID, productID => $productID );

            if ( $urlObject->url ) {
                $item->{ServiceURL} = Common::FormObject::Scalar->new( value => $urlObject->url );

                my $productMonitorItem =
                  BookPub::DB::Item::ProductMonitorItem->Lookup( product_monitor_item_id => $currentPrice->product_monitor_item_id );
                $item->{LastVerified} = Common::FormObject::Scalar::Date->new( value => $productMonitorItem->last_verified );
            }
        }

        # We only want to display the price if this is a service that does physical products
        # OR we somehow have a price anyway (which means something has gone horribly wrong).
        #
        if ( $item->{Price} || $self->_isValidPhysicalServiceID($serviceID) ) {
            push( @result, $item );
        }
    }

    return \@result;
}

sub _getServiceName {
    my $self = shift;
    my $serviceID = shift || die;

    my $service = BookPub::DB::Item::Service->Lookup( service_id => $serviceID );

    unless ($service) {
        BookPub::Tracker::Service::AddService( service_id => $serviceID );
        $service = BookPub::DB::Item::Service->Lookup( service_id => $serviceID );
    }

    die "Unknown Service ID: $serviceID" unless ($service);

    return $service->service_name();
}

sub _getServiceRankings {
    my ( $self, @productIDs ) = @_;
    my @result;
    my $item;

    my @serviceIDs = BookPub::RDAS::Service->GetAllServiceIDs();

    foreach (@serviceIDs) {

        my $item = {};
        my $rank = BookPub::DB::Item::ProductMonitorItemRank->GetCurrent( service_id => $_, product_id => \@productIDs );
        if ($rank) {
            if ( $rank->rank ) {
                $item->{Rank} = Common::FormObject::Scalar::Integer->new( value => $rank->rank );
                my $service = BookPub::DB::Item::Service->Lookup( service_id => $_ );
                if ($service) {
                    $item->{ServiceName} = Common::FormObject::Scalar::String->new( value => $service->service_name );
                }
                push( @result, $item );
            }
        }
    }

    return \@result;
}

sub _getNYTRankings {
    my ( $self, @productIDs ) = @_;
    my @result;
    my $item;

    my $rankings = BookPub::DB::Item::BestSellerBookProduct->GetCurrent( product_id => \@productIDs );
    while ( $rankings->hasNext ) {
        my $rank = $rankings->next();
        my $item = {};
        if ( $rank->rank ) {
            $item->{Rank} = Common::FormObject::Scalar::Integer->new( value => $rank->rank );

            my $list = BookPub::DB::Item::BestSellerList->Lookup( best_seller_list_id => $rank->best_seller_list_id );
            if ($list) {
                $item->{ListName} = Common::FormObject::Scalar::String->new( value => $list->description );
            }

            push( @result, $item );
        }
    }

    return \@result;
}

sub _isValidPhysicalServiceID {
    my $self = shift;
    my $serviceID = shift || return;

    for my $id ( BookPub::RDAS::Service->validPhysicalServices ) {
        return 1 if ( $id == $serviceID );
    }

    return;
}

###
1;    #
###
