#---------------------------------------------------------------
# ____                   _ _         ____  _
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/
#
# Copyright (C) 2013 RoyaltyShare, Inc.   All Rights Reserved
#---------------------------------------------------------------

package RPS::Import::Caroline::v3;

use strict;

use Date::Calc qw(Days_in_Month Decode_Month);

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

use lib '/app/tools/rps/lib';
use RPS::Import::ServiceMap;

use Spreadsheet::ParseExcel;

use base 'RPS::Import::MapFaceBase';
use base 'RPS::Import::Importer';

sub _fieldMap {
    my $self    = shift;
    my $version = $self->_version;

    my %field_map = (
        3 => {
            labelName   => 'A',
            serviceID   => 'D',
            dateBegin   => 'O',
            dateEnd     => 'P',
            upc         => 'I',
            albumName   => 'H',
            trackName   => 'K',
            isrc        => 'N',
            units       => 'Q',
            price       => 'R',
            productType => 'F',
        },
        5 => {
            labelName   => 'A',
            serviceID   => 'E',
            upc         => 'J',
            albumName   => 'I',
            trackName   => 'L',
            isrc        => 'N',
            units       => 'P',
            price       => 'Q',
            productType => 'G',
        },
        12 => {
            labelName   => 'A',
            serviceID   => 'E',
            dateBegin   => 'O',
            upc         => 'J',
            albumName   => 'I',
            trackName   => 'L',
            isrc        => 'N',
            units       => 'P',
            price       => 'O',
            productType => 'G',
        },
        16 => {
            labelName   => 'B',
            serviceID   => 'V',
            dateBegin   => 'T',
            dateEnd     => 'U',
            upc         => 'M',
            albumName   => 'L',
            trackName   => 'O',
            isrc        => 'Q',
            units       => 'X',
            price       => 'W',
            productType => 'I',
        },
    );
    return $field_map{$version};
}

sub _unverifiedFieldMap {
    my $self    = shift;
    my $version = $self->_version;

    my %field_map = (
        3 => {
            albumArtist  => 'G',
            trackArtist  => 'J',
            deliveryType => 'C',
        },
        5 => {
            albumArtist  => 'H',
            trackArtist  => 'K',
            deliveryType => 'D',
        },
        12 => {
            albumArtist  => 'H',
            trackArtist  => 'K',
            deliveryType => 'D',
        },
        16 => {
            albumArtist  => 'K',
            trackArtist  => 'N',
            deliveryType => 'E',
        },
    );
    return $field_map{$version};
}

sub serviceID {
    my $self = shift;

    my $service = $self->_getByFieldName('serviceID');
    my $serviceID = $self->getServiceID( lc($service) ) || $RPS::Import::ServiceMap::SERVICE_ALIASES{ lc $service };
    return $serviceID if ($serviceID);
    return $self->handleError( "Unknown service: $serviceID", RPS::DB::Item::SaleImportError::kErrorService );
}

# Note: keys must be lowercase
#
my %gFormatMediaMap = (
    'ad supported streams' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'broadcast vod' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'conditional mastertone' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'drm-free upgrade transactions' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOADUPGRADE,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ephemeral plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'film non-music video rental' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'fixed plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'kiosk' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'long form music video rental' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'mobile audio streams' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'mobile video streaming' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'non-music video sell-thru' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'ota permanent downloads' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'permanent downloads' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'permanent downloads promo' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'portable sub client plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'portable sub device plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'portable sub programmed plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'portable sub streams' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'portable sub video dvc plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'programmed streaming' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'programmed streaming (non-royalty bearing)' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'programmed streaming-capped (non-royalty bearing)' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'programmed video streaming' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'ringbacks' => {
        formatType => RPS::File::Sale::FORMAT_RINGTONE,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ringback - no copyright' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ringbacks (no cprt liability)' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'standard mobile ringsounds' => {
        formatType => RPS::File::Sale::FORMAT_RINGTONE,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'streams' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'sub user generated streams (umg audio)' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription mastertones' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription ota permanent downloads (audio)' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription programmed streaming' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'tethered/conditional downloads' => {
        formatType => RPS::File::Sale::FORMAT_TETHERED,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'user generated streams (umg audio / user video)' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'video downloads' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'video fixed play' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'video streams' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'video streams (sponsorship)' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
);

sub _headerIdentifier { ( upc => qr/UPC(?: ID)?/ ) }    # "UPC" or "UPC ID"

sub currencyCode { "USD" }

sub countryCode {

    my $self = shift;
    if ( $self->_version == 12 ) {
        if ( !exists $self->{_countryCode} ) {
            if ( $self->filename =~ /_US/i ) {
                $self->{_countryCode} = 'US';
            } elsif ( $self->filename =~ /_CA/i ) {
                $self->{_countryCode} = 'CA';
            } else {
                return $self->handleError( "Unable to determine country code from " . $self->filename,
                    RPS::DB::Item::SaleImportError::kErrorNonqualifying );

            }
        }
        return $self->{_countryCode};
    }
    return "US";
}

sub saleDates {
    my $self    = shift;
    my $version = $self->_version;

    my $dateBegin;
    my $dateEnd;

    if ( $version == 5 || $version == 12 ) {

        # version 5:  date from filename (see _preProcess)
        # version 12: date from header (see _processHeader)
        #
        $dateBegin = $self->{_dateBegin};
        $dateEnd   = $self->{_dateEnd};
    } elsif ( exists $self->_fieldMap->{'dateBegin'} ) {
        my $sdate = $self->_getByFieldName('dateBegin');
        my $edate = $self->_getByFieldName('dateEnd');

        if ( $sdate =~ /(\d{4})-(\d{1,2})-(\d{1,2})/ )    # YYYY-MM-DD
        {
            $dateBegin = sprintf( "%04d-%02d-%02d", $1, $2, 1 );

        } elsif ( $sdate =~ /^(\d{5})$/ ) {
            $dateBegin = Spreadsheet::ParseExcel::Utility::ExcelFmt( "yyyy-mm-dd", $sdate );
            my ( $year, $month, $day ) = split( "-", $dateBegin );
            $dateBegin = sprintf( "%04d-%02d-01", $year, $month );
        }

        if ( $edate =~ /(\d{4})-(\d{1,2})-(\d{1,2})/ )    # YYYY-MM-DD
        {
            $dateEnd = sprintf( "%04d-%02d-%02d", $1, $2, Days_in_Month( $1, $2 ) );
        } elsif ( $edate =~ /^(\d{5})$/ ) {
            $dateEnd = Spreadsheet::ParseExcel::Utility::ExcelFmt( "yyyy-mm-dd", $edate );
            my ( $year, $month, $day ) = split( "-", $dateEnd );
            $dateEnd = sprintf( "%04d-%02d-%02d", $year, $month, Days_in_Month( $year, $month ) );
        }
    }

    return ( $dateBegin, $dateEnd );

}

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

    $self->SUPER::_processHeader(%args);

    if ( $self->_version == 12 ) {

        # For version 12, the date is actually in the header
        #
        return if ( !$self->{_headerFound} );

        my $dt = $self->_getByFieldName('dateBegin');

        if ( $dt =~ /revenue umg \w{2} \d{2} \((\w{3}) (\d{2})\)/i ) {
            my $_month = lc $1;
            my $year   = $2;

            my %months = (
                jan => 1,
                feb => 2,
                mar => 3,
                apr => 4,
                may => 5,
                jun => 6,
                jul => 7,
                aug => 8,
                sep => 9,
                oct => 10,
                nov => 11,
                dec => 12
            );
            my $month = $months{$_month};
            $year += 2000;

            my $sdate = sprintf( "%04d-%02d-01", $year, $month );
            my $edate = sprintf( "%04d-%02d-%02d", $year, $month, Days_in_Month( $year, $month ) );

            $self->{_dateBegin} = $sdate;
            $self->{_dateEnd}   = $edate;
        } else {
            return $self->handleError( "Unable to determine date", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
        }
    }
}

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

    $self->SUPER::_preProcess(%args);

    if ( $self->_version == 5 ) {
        if ( $self->filename =~ /(\d{4})_(\d{2})(\s|_)/ ) {
            $self->{_dateBegin} = sprintf( "%04d-%02d-%02d", $1, $2, 1 );
            $self->{_dateEnd} = sprintf( "%04d-%02d-%02d", $1, $2, Days_in_Month( $1, $2 ) );
        }
    }
}

sub _processSheet {
    my $self     = shift;
    my $sheet    = shift;
    my $sheetnum = shift;

    if ( $self->version == 12 ) {
        return $self->SUPER::_processSheet( $sheet, $sheetnum ) if ( $self->{sheetname} =~ /digital sales/i );
    } else {
        return $self->SUPER::_processSheet( $sheet, $sheetnum );
    }
}

sub artistName {
    my $self = shift;
    if ( $self->upc eq $self->isrc ) {
        return $self->_getByFieldName('albumArtist');
    } else {
        my $name = $self->_getByFieldName('trackArtist');
        if ( $name =~ /(\w+),\s*(\w+)/ ) {
            $name = "$2 $1";
        } elsif ( $name =~ /^-+$/ )    # bunch 'o hyphens ...
        {
            $name = $self->_getByFieldName('albumArtist');
        }
        return $name;
    }
}

sub productType {
    my $self = shift;
    my $type = $self->_getByFieldName('productType') || return;

    if ( $type =~ /^track$/i ) {
        return RPS::File::Sale::TYPE_TRACK;
    } elsif ( $type =~ /^bundles$/i ) {

        # Bundles are albums unless they have an isrc that looks like an isrc
        # (as opposed to something like an upc)

        return ( $self->SUPER::isrc =~ /^[a-z]{2}.+/i ) ? RPS::File::Sale::TYPE_TRACK : RPS::File::Sale::TYPE_ALBUM;
    } elsif ( $type =~ /^complete album$/i ) {
        return RPS::File::Sale::TYPE_ALBUM;
    }
    return $self->handleError( "Unable to determine product type from '$type'", RPS::DB::Item::SaleImportError::kErrorProductType );
}

sub units {
    my $self = shift;
    my $u    = $self->_getByFieldName('units') || 0;
    my $p    = $self->_getByFieldName('price');

    # Follow the sign of the revenue...
    #
    if ( $p > 0 ) {
        return 1 if ( !$u );    # force a unit if there's revenue
        return ( $u < 0 ) ? abs($u) : $u;
    } elsif ( $p < 0 ) {
        return -1 if ( !$u );    # force a unit if there's revenue
        return ( $u < 0 ) ? $u : ( $u * -1 );
    }
    return $u;
}

sub unitPrice { abs( shift->SUPER::unitPrice ) }

# Don't flag free sales (FB15405)
#sub free {
#    my $self = shift;
#    my $u = $self->_getByFieldName('units') || 0;
#    my $p = $self->_getByFieldName('price');
#    return ($u != 0 && $p == 0) ? 1 : 0;
#}

sub _isValidSaleRecord {
    my $self = shift;

    # We may not know if this is an album or track, so we need to be a bit
    # more agnostic with out tests,
    if ( $self->albumName || $self->upc || $self->trackName || $self->isrc ) {
        return 1;
    }

    # How would we ever get here?
    if ( $self->_version == 12 ) {
        my $u = $self->_getByFieldName('units') || 0;
        my $p = $self->_getByFieldName('price');

        return 1 if ( !$p && $u );    # ok if units but no revenue (will be marked free)
    }

    return $self->SUPER::_isValidSaleRecord();
}

sub formatType {
    my $self = shift;
    my ( $formatID, $mediaType ) = $self->_getFormatMedia();

    if ( !$formatID ) {
        my $deliveryType = lc $self->_getByFieldName('deliveryType');
        return $self->handleError( "Unrecognized channel '$deliveryType", RPS::DB::Item::SaleImportError::kErrorFormatType );
    }

    return $formatID;
}

sub mediaType {
    my $self = shift;
    my ( $formatID, $mediaType ) = $self->_getFormatMedia();

    if ( !$mediaType ) {
        my $deliveryType = lc $self->_getByFieldName('deliveryType');
        return $self->handleError( "Unrecognized channel '$deliveryType", RPS::DB::Item::SaleImportError::kErrorMediaType );
    }

    return $mediaType;
}

sub _getFormatMedia {
    my ($self) = @_;
    my $deliveryType = lc $self->_getByFieldName('deliveryType');

    if ( $deliveryType =~ /mobile images/i ) {
        return $self->handleError( "Unsupported format_type '$deliveryType'", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
    }

    my $formatID;
    my $mediaType;
    if ( exists $gFormatMediaMap{$deliveryType} ) {
        $formatID  = $gFormatMediaMap{$deliveryType}->{formatType};
        $mediaType = $gFormatMediaMap{$deliveryType}->{mediaType};
    }

    return ( $formatID, $mediaType );
}

sub trackName {
    my $self  = shift;
    my $title = $self->SUPER::trackName;

    return ( $self->upc ne $self->isrc && $title ne 'NA' && $self->isrc ne '-' ) ? $title : undef;
}

sub isrc {
    my $self  = shift;
    my $title = $self->SUPER::trackName;

    return ( $self->upc ne $self->SUPER::isrc && $title ne 'NA' && $self->SUPER::isrc ne '-' ) ? $self->SUPER::isrc : undef;
}

## MapFace Stuff

sub _mapFaceServiceID {
    return ('serviceID');
}

sub _mapFaceCountryCode {
    return;
}

sub _mapFaceProductType {
    return ('productType');
}

sub _mapFaceFormatType {
    return ('deliveryType');
}

sub _mapFaceMediaType {
    return ('deliveryType');
}

sub _mapFaceCompatibleVersions {
    return ( 3, 5, 9, 12, 16 );
}

###
1;    # Play nicely.
###
