package BookPub::Sale::Report::Royalty::BloomsburyUK;

use strict;
use warnings;

use Data::Dumper;

use IO::File;
use File::Path;

use lib '/app/tools/common/lib';
use lib '/app/tools/bookpub/lib';
use Common::RSMath;
use BookPub::DB::Item::Service;
use BookPub::DB::Item::BookContributor;
use BookPub::DB::Item::RoyaltyReport::RSStandard;
use BookPub::DB::Item::BookFormat;
use BookPub::DB::Item::BookFormatType;
use BookPub::DB::Item::BookFormatSubtype;
use BookPub::DB::Item::OnixCode;
use BookPub::Config;
use Common::Util;
use Common::Assert;
use Common::Client;
use Common::Locale;
use Common::Log;

use base 'BookPub::Sale::Report::Royalty';

# We'll keep a separate tally of units and revenue and
# return those at the end for validation.
my $totalUnits;
my $totalRevenueUnrounded;

sub create {
    my ($self) = @_;

    # Make sure we have a directory to write the final file into.
    my $baseDir = $self->_baseDir();
    if ( !-d $baseDir ) {
        File::Path::mkpath($baseDir) || die "ERROR - make_path failed for $baseDir: $!";
    }

    my $dest_file_path = $self->filePath();

    my $writeFH;
    unless ( $writeFH = IO::File->new(">$dest_file_path") ) {
        die "can't create file $dest_file_path: $!\n";
    }
    binmode( $writeFH, ':utf8' );

    # Output the header
    my $header = $self->getHeader();
    print $writeFH "$header\r\n";

    while ( my $row = $self->getNextRow() ) {
        print $writeFH "$row\r\n";
    }

    close($writeFH);

    # Going to send everything back in a hash so that's it's
    # easy to add more stuff in later.
    my %returnValues;
    $returnValues{totalUnits}            = $totalUnits;
    $returnValues{totalRevenueUnrounded} = $totalRevenueUnrounded;

    return (%returnValues);

}

sub _seperator {
    return "\t";
}

sub _getTypesFromBookFormat {
    my ( $self, $bookFormatID ) = @_;

    if ( !$self->{_bookFormats}{$bookFormatID} ) {
        my $bookFormat = BookPub::DB::Item::BookFormat->Lookup( book_format_id => $bookFormatID );
        my $bookFormatType = BookPub::DB::Item::BookFormatType->Lookup( book_format_type_id => $bookFormat->book_format_type_id() );
        my $onixCode = BookPub::DB::Item::OnixCode->Lookup( onix_code_id => $bookFormatType->onix_code_id() );
        my $formatString = $onixCode->description();
        my $epubString;
        if ( $bookFormat->book_format_subtype_id() ) {
            my $bookFormatSubtype =
              BookPub::DB::Item::BookFormatSubtype->Lookup( book_format_subtype_id => $bookFormat->book_format_subtype_id() );
            my $onixCode = BookPub::DB::Item::OnixCode->Lookup( onix_code_id => $bookFormatSubtype->onix_code_id() );
            if ( 10 == $onixCode->code_list() ) {
                $epubString = $onixCode->code_value();
            }
        }

        $self->{_bookFormats}{$bookFormatID} = [ $formatString, $epubString ];
    }

    my $formats = $self->{_bookFormats}{$bookFormatID};

    return ( $formats->[0], $formats->[1] );
}

sub getHeader {
    my ($self) = @_;

    if ( !$self->{header} ) {

        # We've got TWO header lines.
        # We'll need to calculate the total units and the total payment (in the native currency).
        my $totalUnits;
        my $totalRevenue;

        my $allFiles = BookPub::DB::Item::File->GetByPeriodID( $self->periodID() );
        while ( my $file = $allFiles->next() ) {
            $totalUnits += $file->units();
            if ( $file->input_conversion_rate() ) {
                my $inputConversionRates = BookPub::DB::Item::InputConversionRate->GetAllByFileID( $file->file_id() );
                while ( my $conversion = $inputConversionRates->next() ) {
                    my $convertedRevenue = $conversion->revenue() * $conversion->conversion_rate();
                    $totalRevenue += $convertedRevenue;
                }
            } else {
                $totalRevenue += $file->revenue();
            }
        }

        my @topHeader;
        push @topHeader, 'Report Provider';
        push @topHeader, 'RoyaltyShare';
        push @topHeader, 'Total Units';
        push @topHeader, Common::Util::formatFixedPoint( $totalUnits, 2 );
        push @topHeader, 'Total Payment';
        push @topHeader, Common::Util::formatFixedPoint( $totalRevenue, 4 );
        push @topHeader, 'Payment Currency';
        push @topHeader, Common::Client::Current()->Locale()->currencyFormat()->currencyCode();

        my $delim = $self->_seperator();
        $self->{header} = join( $delim, @topHeader );

        my @secondHeader;
        push @secondHeader, 'Sale Start Date';
        push @secondHeader, 'Sale End Date';
        push @secondHeader, 'Distributor Name';
        push @secondHeader, 'Service Name';
        push @secondHeader, 'ISBN 13';
        push @secondHeader, 'ISBN 10';
        push @secondHeader, 'Title';
        push @secondHeader, 'Sub-Title';
        push @secondHeader, 'Author Name';
        push @secondHeader, 'Publisher Name';
        push @secondHeader, 'Imprint Name';
        push @secondHeader, 'Product Type';
        push @secondHeader, 'Epub Type';
        push @secondHeader, 'Country Code';
        push @secondHeader, 'Units';
        push @secondHeader, 'Price Type';
        push @secondHeader, 'List Price';
        push @secondHeader, 'List Price Currency';
        push @secondHeader, 'Publisher Discount';
        push @secondHeader, 'Net Price (List Currency)';
        push @secondHeader, 'Currency Conversion';
        push @secondHeader, 'Net Price (Payment Currency)';
        push @secondHeader, 'Net Payment';
        push @secondHeader, 'Fees';

        $self->{header} .= "\r\n" . join( $delim, @secondHeader );
    }
    return $self->{header};
}

sub _getSalesCollection {
    my ($self) = @_;
    return BookPub::DB::Item::RoyaltyReport::RSStandard->GetReportData( $self->periodID() );
}

sub getNextRow {
    my ($self) = @_;

    if ( !$self->{streamCollection} ) {
        $self->{streamCollection} = $self->_getSalesCollection();
    }
    return undef unless $self->{streamCollection}->hasNext();

    if ( !$self->{services} ) {
        # Grab all the services, so we don't have to look up each file and sale service for each row.
        my $allServices = BookPub::DB::Item::Service->GetAll();
        while ( my $service = $allServices->next() ) {
            $self->{services}{ $service->service_id } = $service->service_name;
        }
    }

    my $row = $self->{streamCollection}->next();
    my @outRow;

    push @outRow, $row->sale_start_date();
    push @outRow, $row->sale_end_date();

    # If there is a service_id set at the sale level, then the file's service_id is actually the _distributor_.
    # Otherwise, the file's service id represents the service, and there isn't a distributor.
    if ( $row->sale_service_id() && $row->sale_service_id() != $row->file_service_id() ) {
        push @outRow, $self->{services}{ $row->file_service_id() };
        push @outRow, $self->{services}{ $row->sale_service_id() };
    } else {
        push @outRow, '';
        if ( $row->orig_file_name() =~ /^(Lending|Revshare)[ _]HDZEU[ _]DigitalEBooksPaymentReport/i
            || $row->orig_file_name() =~ /^(Prime)_eBooksPrimeReadingReport-HDZEU/i ) {
            push @outRow, $self->{services}{ $row->file_service_id() } . " - $1";
        } else {
            push @outRow, $self->{services}{ $row->file_service_id() };
        }
    }

    push @outRow, $row->isbn13();
    push @outRow, $row->isbn10();

    # Strip tabs, new line, etc from title
    my $title = $row->title();
    $title =~ s/\s/ /g;
    push @outRow, $title;

    # Strip tabs, new line, etc from subtitle
    my $subtitle = $row->subtitle() || '';
    $subtitle =~ s/\s/ /g;
    push @outRow, $subtitle;

    # Just going to have to fetch the author name(s)
    my $authors = BookPub::DB::Item::BookContributor->GetAuthorNamesByBookID( $row->book_id );
    $authors = substr( $authors, 0, 149 );
    push @outRow, $authors;

    push @outRow, $row->publisher();
    push @outRow, $row->imprint();

    # Need to fetch the product type and subtype... We'll use an internal method so we can cache the results.
    #
    my ( $productType, $epubType ) = $self->_getTypesFromBookFormat( $row->book_format_id() );
    push @outRow, $productType;
    push @outRow, $epubType;

    push @outRow, $row->country();
    push @outRow, $row->units();
    push @outRow, $row->price_type();
    push @outRow, Common::Util::formatFixedPoint( $row->list_price(), 4 );
    push @outRow, $row->currency();
    push @outRow, Common::Util::formatFixedPoint( $row->discount(), 4 );
    push @outRow, Common::Util::formatFixedPoint( $row->net_price(), 4 );
    push @outRow, Common::Util::formatFixedPoint( $row->conversion_rate(), 4 );
    push @outRow, Common::Util::formatFixedPoint( $row->net_price() * $row->conversion_rate(), 4 );
    push @outRow, $row->revenue() * $row->conversion_rate();
    push @outRow, $row->fee();

    $self->_truncateFieldValues(\@outRow);

    $totalUnits += $row->units();
    $totalRevenueUnrounded += $row->revenue() * $row->conversion_rate();

    no warnings;
    return join( $self->_seperator(), @outRow );
}

sub _truncateFieldValues {
    my ($self, $aRow) = @_;

    foreach my $value ( @$aRow ) {
        next unless defined $value && length $value;
        $value = substr($value, 0, 150);
    }

    return $aRow;
}


1;