package BookPub::Catalog::Import::Parser::FlatFile::HayHouseAudio;

use strict;

use Spreadsheet::ParseExcel;

#use Spreadsheet::ParseExcel::WorkBook;
use Data::Dumper;
use Date::Calc;

use lib '/app/tools/common/lib';
use lib '/app/tools/bookpub/lib';
use Common::UTF8;
use Common::Log;
use Common::Util;
use Common::Assert;
use base 'BookPub::Catalog::Import::Parser::FlatFile';

# !!! Really all this is used for is to return the sentdate value.
#
sub header {
    my ($self) = @_;

    return { sentdate => $self->{sentdate} };
}

sub nextProduct {
    my $self = shift;

    my $row = $self->_nextRow();
    return undef unless $row;

    Common::Log::Print( "------- so-called publication date = ", $row->[4] );

    # Map the columns properly.
    #
    my $prodRef = {

        #        product =>
        #        {
        title => {
            titletype => '01',
            titletext => $row->[0],
        },
        publicationdate   => $row->[4],
        productidentifier => {
            idtype  => 'ISBN-13',
            idvalue => $row->[1],
        },
        productform  => 'AJ',                                                # AJ == downloadable audio file.  Might not be the best choice?
        contributor  => $self->_parseContributors( $row->[2], $row->[3] ),
        supplydetail => {
            suppliername        => 'Hay House',
            supplierrole        => '01',
            supplytocountry     => 'US',
            availabilitycode    => 'NP',
            productavailability => '10',
            price               => {
                pricetypecode => '01',
                pricestatus   => '01',
                priceamount   => $row->[6],
                currencycode  => 'USD',
                countrycode   => 'US',
            },
        },
        publisher => {
            pubrole       => '01',
            publishername => 'Hay House',
        },
        imprint => {
            imprintname => 'Hay House',
        },

        #        },
    };

    return $prodRef;
}

sub _parseContributors {
    my ( $self, $authors, $narrators ) = @_;

    my $sequence = 1;
    my @contributors;

    my $authorList = $self->_splitContributorString($authors);

    my $withFlag = 0;

    # Note that a 'with' denotes a contributor code of A02.
    #
    $withFlag = 1 if $authors =~ / with /;
    for ( my $i = 0 ; $i < scalar @$authorList ; $i++ ) {
        my $code = 'A01';
        if ( $withFlag && $i > 0 ) {
            $code = 'A02';
        }

        push @contributors,
          {
            contributorrole          => $code,
            sequencenumber           => $sequence,
            $authorList->[$i]->{tag} => $authorList->[$i]->{name},
          };

        $sequence++;
    }

    my $narratorList = $self->_splitContributorString($narrators);
    for ( my $i = 0 ; $i < scalar @$narratorList ; $i++ ) {
        my $code = 'E07';

        push @contributors,
          {
            contributorrole            => $code,
            sequencenumber             => $sequence,
            $narratorList->[$i]->{tag} => $narratorList->[$i]->{name},
          };

        $sequence++;
    }

    return \@contributors;
}

sub _splitContributorString {
    my ( $self, $string ) = @_;

    # There are several different patterns I can discern here:
    #
    # Last, First
    # First Last
    # First Last, First Last
    # Last, First; Last, First
    # First Last and First Last
    # Last, First & First
    # First Last with First Last
    # First Last, Ph.D.
    # First Last, M.D.
    # Last/Last/Last/Last
    # Last, First (something else?)

    my @returnList;

    if ( $string =~ /(.*) and (.*)/ ) {
        my $firstName  = $1;
        my $secondName = $2;
        $firstName =~ s/,$//;
        $secondName =~ s/,$//;
        push @returnList, { tag => 'personname', name => Common::Util::trimspaces($firstName) };
        push @returnList, { tag => 'personname', name => Common::Util::trimspaces($secondName) };
    } elsif ( $string =~ /(.*) with (.*)/ ) {
        my $firstName  = $1;
        my $secondName = $2;
        $firstName =~ s/,$//;
        $secondName =~ s/,$//;
        push @returnList, { tag => 'personname', name => Common::Util::trimspaces($firstName) };
        push @returnList, { tag => 'personname', name => Common::Util::trimspaces($secondName) };
    } elsif ( $string =~ /;/ ) {
        my @allNames = split( ';', $string );
        foreach my $name (@allNames) {
            push @returnList, { tag => 'personnameinverted', name => Common::Util::trimspaces($name) };
        }
    } elsif ( $string =~ /(.*), (.*) & (.*)/ ) {
        my $lastName    = Common::Util::trimspaces($1);
        my $firstFirst  = Common::Util::trimspaces($2);
        my $secondFirst = Common::Util::trimspaces($3);
        push @returnList, { tag => 'personname', name => "$firstFirst $lastName" };
        push @returnList, { tag => 'personname', name => "$secondFirst $lastName" };
    } else {

        # So much for the 'easy' cases.  Now we need to look a bit more closely.
        # I might have several names separated by commas, or just one last, first, or
        # some other wackadoodle structure.
        # (!!!) The name/name/name/name thing is stupid, and I will treat that as a single name for now.
        #
        my @commaChunks = split( ',', $string );
        if ( 1 == scalar @commaChunks ) {
            push @returnList, { tag => 'personname', name => $string };
        } else {

            # So we'll look at the first chunk.  If that has multiple words, then we have
            # either a set of 'first last, first last', or perhaps a ',.Ph.D'.
            #
            my @spaceChunks  = split( / /, Common::Util::trimspaces( $commaChunks[0] ) );
            my @spaceChunks2 = split( / /, Common::Util::trimspaces( $commaChunks[1] ) );
            if ( 1 == scalar @spaceChunks ) {

                # Guessing this is a single last, first
                #
                push @returnList, { tag => 'personnameinverted', name => Common::Util::trimspaces($string) };
            } else {
                if ( 2 == scalar @spaceChunks ) {

                    # This is either two names, or one name with an honorific
                    # OR, it could be a wacky double last name, like 'Randolph Price, John'
                    #
                    my $name1 = Common::Util::trimspaces( $spaceChunks[0] );
                    my $name2 = Common::Util::trimspaces( $spaceChunks[1] );

                    if ( 1 == scalar @spaceChunks2 ) {
                        if ( $name2 =~ /\..\./ ) {

                            # One nifty name
                            #
                            push @returnList, { tag => 'personname', name => Common::Util::trimspaces($string) };
                        } else {
                            push @returnList, { tag => 'personnameinverted', name => Common::Util::trimspaces($string) };
                        }
                    } else {
                        push @returnList, { tag => 'personname', name => $name1 };
                        push @returnList, { tag => 'personname', name => $name2 };
                    }
                } else {

                    # A list of several comma-separated regular names
                    #
                    foreach my $name (@commaChunks) {
                        push @returnList, { tag => 'personname', name => Common::Util::trimspaces($name) };
                    }
                }
            }
        }

    }

    return \@returnList;
}

sub _init {
    my ( $self, %args ) = @_;

    my $file = $args{file};
    assert( $file, "ERROR - missing file parameter" );

    $self->{filePath} = $file;

    # If the filename doesn't have a date stamp, we can't continue.
    #
    if ( $file =~ /(\d\d\d\d\d\d\d\d)_.*\.xls$/ ) {
        $self->{sentdate} = $1;
    } else {
        die "ERROR - filename does not contain a timestamp, or doesn't appear to be an .xls file";
    }

    # Prime the row iterator, then read the header line.
    # We can make sure the header matches our expectations.
    #
    my $workbook = Spreadsheet::ParseExcel::Workbook->Parse( $self->{filePath} );
    if ( !$workbook ) {
        die "ERROR - unable to parse file $file as an Excel file";
    }
    if ( !$workbook->{Worksheet} ) {
        die "ERROR - unable to find a 'Worksheet' in file $file";
    }

    $self->{workbook} = $workbook;
    $self->{rowIndex} = 0;

    # Now we can start looking for the header.
    #
    my $firstSheet = $workbook->{Worksheet}->[0];

    # !!! DEBUG - Spew forth the data!
    #
    my $foundHeader = 0;
    while ( my $row = $self->_nextRow() ) {
        if (   $row->[0] eq 'Title'
            && $row->[1] eq '13-ISBN Digital'
            && $row->[2] eq 'Author Name'
            && $row->[3] eq 'Narrator'
            && $row->[4] eq 'Pub Date'
            && $row->[5] eq '13-ISBN Print'
            && $row->[6] eq 'RRP (USD)' ) {
            $foundHeader = 1;
            last;
        }
    }

    if ( !$foundHeader ) {
        die "ERROR - Unable to find the Header row in file $file";
    }

    return $self;
}

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

    # Everything ought to be in the first sheet.
    #
    my $sheet = $self->{workbook}->{Worksheet}->[0];

    # If we've read all the lines, we're done.
    #
    if ( !defined $sheet->{MaxRow} || $self->{rowIndex} > $sheet->{MaxRow} ) {
        return undef;
    }

    # If we run into a blank line, then we're also going to call it quits.
    #
    my $hasData;
    my @row;

    for ( my $colIndex = 0 ; defined $sheet->{MaxCol} && $colIndex <= $sheet->{MaxCol} ; $colIndex++ ) {
        my $cell = $sheet->{Cells}[ $self->{rowIndex} ][$colIndex];
        if ($cell) {

            # !!! This code is lifted from BookPub::Sale::File.
            #
            my $value = $cell->{Val};

            if ( $cell->{Code} eq 'ucs2' ) {
                $value = Common::UTF8::Encode( $value, Common::UTF8::kEncodingUCS2 );
            }

            #            if (lc($cell->{Type}) eq 'date')
            if ( 4 == $colIndex ) {
                my $heldValue = $value;
                $value = Spreadsheet::ParseExcel::Utility::ExcelFmt( "yyyy-mm-dd", $value );
                if ( $self->{workbook}{Flg1904} ) {
                    my ( $y, $m, $d ) = Add_Delta_Days( 1904, 1, 1, $heldValue );
                    $value = sprintf( "%04d-%02d-%02d", $y, $m, $d );
                }
            } else {

                # Trim quotes, remove wacky white space, etc.
                #

                $value =~ s/[\n\r\t]+/ /g;
                $value =~ s/^\s+//;
                $value =~ s/\s+$//;
                $value = Common::Util::trimquotes($value);
            }

            my $file = $self->{filePath};

            if ( $file =~ /\.xlsx$/ ) {
                $value =~ s/&amp;/&/;
                $value =~ s/&lt;/</;
                $value =~ s/&gt;/>/;
                $value =~ s/&apos;/'/g;
                $value =~ s/&quot;/"/g;
            }

            push @row, $value;
            $hasData++;
        } else {
            push @row, '';
        }
    }

    $self->{rowIndex}++;

    return undef unless $hasData;

    return \@row;
}

1;
