#------------------------------------------------------------
# Copyright (C) 2009 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package Distribution::Export::Exporter;
use strict;
use warnings;

use File::Copy;
use Data::Dumper;

use lib '/app/tools/common/lib';
use Common::RSApp;
use Common::Util;
use Common::Assert;
use Common::WriteXML;

use RPS::Product::DistributionService;
use Distribution::DistributionProcess::ServiceAccount;
use Distribution::DB::Item::ServiceAccount;

use lib '/app/tools/rps/lib';

use lib '/app/tools/distribution/lib';

use RPS::DB::Item::ProductTrack;
use RPS::DB::Item::Product;

use MediaServe::Server;

use MediaServe::DB::Item::MediaFile;
use MediaServe::DB::Item::AlbumFile;
use MediaServe::DB::Item::ProductTrackFile;

use Distribution::DB::Item::ProductDistribution;

use base 'Common::Script';

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

    $self->{_destDir} = $args{dest_dir};

    assert( $args{dest_dir},  "Destination Dir required" );
    assert( $args{client_id}, "Client ID required" );

    return $self->SUPER::_init(@_);
}

sub _process {
    my $self = shift;

    $self->log( "Processing client: " . Common::RSApp::GetClientID );

    if (
           $self->_makeDestDir()
        && $self->_storeDeliveryReport()
        && $self->_storeAudioAssets()
        &&

        #$self->_storeImageAssets() &&
        #$self->_storeMetadata()
      ) {
        $self->log("Process complete.");
    } else {
        $self->log("Process failed.");
        exit 1;
    }
}

sub _makeDestDir {
    my $self = shift;
    $self->{_outputDir} = $self->{_destDir} . "/" . Common::RSApp::GetClientID;

    system("mkdir -p $self->{_outputDir}");

    unless ( -d $self->{_destDir} ) {
        print STDERR "Can not write to destination directory: $self->{_destDir}\n";
        return;
    }

    return 1;
}

sub _storeAudioAssets {
    my $self = shift;

    my $collection = MediaServe::DB::Item::ProductTrackFile->GetAll();

    while ( my $product_track_file = $collection->next ) {
        my $product_track = RPS::DB::Item::ProductTrack->Lookup( product_track_id => $product_track_file->product_track_id );
        my $product = RPS::DB::Item::Product->Lookup( product_id => $product_track->product_id ) if ($product_track);

        if ($product) {
            my $srcFile = MediaServe::Server::GetAudioPath(
                mediaFileID => $product_track_file->media_file_id,
                clientID    => Common::RSApp::GetClientID,
                type        => 'windows'
            );

            my $destDir = $self->{_outputDir} . "/" . $product->upc_ean;
            system("mkdir -p $destDir");
            die "Could not write to $destDir" unless ( -d $destDir );

            my $destFile = sprintf( "%s_%02d_%03d.flac", $product->upc_ean, $product_track->disc_number, $product_track->disc_track );

            File::Copy::copy( $srcFile, "$destDir/$destFile" );
        }
    }

    return 1;
}

sub _storeImageAssets {
    my $self = shift;

    my $collection = MediaServe::DB::Item::AlbumFile->GetAll();

    while ( my $album_file = $collection->next ) {
        next unless ( $album_file->file_type eq 'original' );

        my $album = RPS::DB::Item::Album->Lookup( album_id => $album_file->album_id );
        my $product = RPS::DB::Item::Product->Lookup( asset_id => $album->album_id, product_type_id => 3 ) if ($album);
        my $mediaFile = MediaServe::DB::Item::MediaFile->Lookup( media_file_id => $album_file->media_file_id );

        my $ext = $mediaFile->filename =~ /tif/ ? "tiff" : "jpeg";

        if ($album) {
            my $srcFile = MediaServe::Server::GetImagePath(
                mediaFileID => $album_file->media_file_id,
                clientID    => Common::RSApp::GetClientID,
                type        => 'windows'
            );

            my $destDir = $self->{_outputDir} . "/" . $product->upc_ean;
            system("mkdir -p $destDir");
            die "Could not write to $destDir" unless ( -d $destDir );

            my $destFile = sprintf( "%s.%s", $product->upc_ean, $ext );

            File::Copy::copy( $srcFile, "$destDir/$destFile" );
        }
    }

    return 1;
}

sub _storeDeliveryReport {
    my $self       = shift;
    my $collection = Distribution::DB::Item::ProductDistribution->getDeliveryReportByService();
    my $via;
    my $service;
    my $type;

    return 1 unless ( $collection->hasNext() );

    my $destFile = $self->{_outputDir} . "/delivery_report.xls";
    open( OUT, ">$destFile" ) || die "Could not create delivery report: $!";
    printf( OUT "%s\t%s\t%s\t%s\n", 'UPC', 'Service', 'Delivery Method', 'Delivery Date' );

    while ( my $row = $collection->next() ) {
        $service = new RPS::Product::DistributionService( serviceID => $row->service_id );
        $type = Distribution::DB::Item::ServiceAccount->GetAccountType(
            client_id  => Common::RSApp::GetClientID,
            service_id => $service->ServiceID
        );
        $via = $type eq 'royaltyshare' ? "RoyaltyShare" : "Direct via RoyaltyShare";
        $via = "Third Party" if ( $row->third_party );

        printf( OUT "%s\t%s\t%s\t%s\n", $row->{upc_ean}, $service->ServiceName, $via, $row->delivery_date );
    }

    close(OUT);

    return 1;
}

sub _storeMetadata {
    my $self = shift;

    my $self = shift;

    my $collection = RPS::DB::Item::ProductDistribution->GetAll();

    print _getMetadataXML();

    return 1;
}

sub _getMetadataXML {
    my ( $productID, $serviceID ) = @_;
    assert( $productID && $serviceID );

    my $product = RPS::DB::Item::Product->Lookup( product_id => $productID );
    assert( $product->product_type_id == RPS::DB::Item::Product::kProductTypeDigital );

    #
    # Quick hack to add apple vendor id.  This should be removed when more services
    # start using custom IDs
    #
    my $appleAlbumID;
    if ( $serviceID == 11 ) {
        my $productServiceID =
          Distribution::DB::Item::ProductServiceID->Lookup( service_id => $serviceID, product_id => $product->product_id );
        $appleAlbumID = $productServiceID->code() if ($productServiceID);
    }

    # Build the territory list
    #
    my $productDigital = RPS::DB::Item::ProductDigital->Lookup( product_id => $productID );
    assert($productDigital);
    my @territoryList;
    my $territories = $productDigital->territories_list;
    if ($territories) {
        @territoryList = split( ' ', $territories );
    }
    my $territoryAllowedFlag = ( RPS::DB::Item::ProductDigital::kTerritoriesFlagAllow eq $productDigital->territories_flag ? 1 : 0 );

    my $albumID = $product->asset_id;
    my $album = RPS::DB::Item::Album->Lookup( album_id => $albumID );

    my $label = RPS::DB::Item::Label->Lookup( label_id => $album->label_id );

    my $albumExplicitFlag = RPS::DB::Item::Album->GetAlbumParentalAdvisory($albumID);
    if ( 'E' eq $albumExplicitFlag ) {
        $albumExplicitFlag = 'explicit';
    } elsif ( 'C' eq $albumExplicitFlag ) {
        $albumExplicitFlag = 'clean';
    } else {
        $albumExplicitFlag = 'none';
    }

    # Let's derive the correct genre - we'll force all the tracks to be this genre too.
    #
    my $isComposerRequired;
    my @genreNames;
    if ( $album->genre_primary_id ) {
        my $genre = RPS::DB::Item::Genre->Lookup( genre_id => $album->genre_primary_id );

        # !!! Not all albums have this yet.
        #
        if ($genre) {
            push @genreNames, $genre->genre_name;

            $isComposerRequired = RPS::DB::Item::Genre::isComposerRequired( genre_id => $album->genre_primary_id );
        }
    }

    my @genreNames_secondary;
    if ( $album->genre_secondary_id ) {
        my $genre = RPS::DB::Item::Genre->Lookup( genre_id => $album->genre_secondary_id );

        # !!! Not all albums have this yet.
        #
        if ($genre) {
            push @genreNames_secondary, $genre->genre_name;

            if ( RPS::DB::Item::Genre::isComposerRequired( genre_id => $album->genre_secondary_id ) ) {
                $isComposerRequired = 1;
            }
        }
    }

    # Need the 'volume' data, from the product_track table.
    #
    # !!! Going to add a new accessor to include some order_by args
    my $productTracks = RPS::DB::Item::ProductTrack->GetTracksByProductID( $productID, "disc_number, disc_track" );

    my @volumes;

    # So, we'll iterate over the product_tracks, and assemble everything we need to know.
    #
    while ( my $productTrack = $productTracks->next() ) {
        my $trackID = $productTrack->track_id;

        # If this is a bonus track, make sure it belongs at this service.
        #
        if ( $productTrack->is_bonus_track ) {
            my $bonusTrackData =
              RPS::DB::Item::BonusTrack->Lookup( product_id => $productID, track_id => $trackID, service_id => $serviceID );
            if ( !$bonusTrackData ) {
                next;
            }
        }
        my $discNum    = $productTrack->disc_number;
        my $volumeData = $volumes[ $discNum - 1 ];
        if ( !defined $volumeData ) {

            # This is a new volume entry.
            # Need id, total length, and the list of tracks.
            #
            $volumeData             = {};
            $volumeData->{id}       = $discNum;
            $volumeData->{sequence} = $discNum;

            # We'll calculate this later.
            #
            $volumeData->{'total-length'} = 0;

            $volumeData->{track} = [];

            push @volumes, $volumeData;
        }

        # Fill in the track info.
        # We'll need track and master data.
        #
        my $tracks    = $volumeData->{track};
        my $trackData = {};

        my $track = RPS::DB::Item::Track->Lookup( track_id => $productTrack->track_id );
        my $master = RPS::DB::Item::Master->Lookup( master_id => $track->master_id );
        my $song = RPS::DB::Item::Song->Lookup( song_id => $master->song_id );
        my $trackArtist = RPS::DB::Item::Artist->Lookup( artist_id => $track->artist_id );

        my $composerName;
        if ( $song->composer_id ) {
            my $composer = RPS::DB::Item::Composer->Lookup( composer_id => $song->composer_id );
            if ($composer) {
                $composerName = $composer->name;
            }
        }

        my $trackExplicitFlag = $track->parental_advisory;
        if ( 'E' eq $trackExplicitFlag ) {
            $trackExplicitFlag = 'explicit';
        } elsif ( 'C' eq $trackExplicitFlag ) {
            $trackExplicitFlag = 'clean';
        } else {
            $trackExplicitFlag = 'none';
        }

        #
        # Quick hack to add apple vendor id.  This should be removed when more services
        # start using custom IDs
        #
        my $appleTrackID;
        if ( $serviceID == 11 ) {
            my $productTrackServiceID = Distribution::DB::Item::ProductTrackServiceID->Lookup(
                service_id       => $serviceID,
                product_track_id => $productTrack->product_track_id
            );
            $appleTrackID = $productTrackServiceID->code() if ($productTrackServiceID);
        }

        $trackData->{'is-explicit'}    = $trackExplicitFlag;
        $trackData->{'sell-unbundled'} = 'yes';
        $trackData->{'title'}          = $track->title;
        $trackData->{'isrc'}           = $master->isrc;
        $trackData->{'sequence'}       = $productTrack->disc_track;
        $trackData->{'length'}         = $master->duration;           # We'll translate this into stupid mode later.

        $trackData->{'genre'} = \@genreNames;

        $trackData->{'label'}          = $label->label_name;
        $trackData->{'cline'}          = $album->c_line;
        $trackData->{'pline'}          = $album->p_line;
        $trackData->{'display-artist'} = $trackArtist->name;
        $trackData->{'composer'}       = $composerName;
        $trackData->{'apple-track-id'} = $appleTrackID;
        $trackData->{'album-only'}     = $productTrack->album_only;

        $trackData->{'additional-artists'} = getAdditionalArtists( track_id => $trackID, service_id => $serviceID );

        # Need to fetch the media_file_id that corresponds to this track's audio.
        #
        my $productTrackFile = MediaServe::DB::Item::ProductTrackFile->Lookup(
            product_track_id => $productTrack->product_track_id,
            file_type        => MediaServe::DB::Item::ProductTrackFile::kFileTypeOriginal,
        );

        my $mediaFileID = $productTrackFile->media_file_id;
        my $audioPath =
          MediaServe::Server::GetAudioPath( mediaFileID => $mediaFileID, clientID => Common::RSApp::GetClientID(), type => 'linux' );
        my $audioWinPath =
          MediaServe::Server::GetAudioPath( mediaFileID => $mediaFileID, clientID => Common::RSApp::GetClientID(), type => 'windows' );
        $trackData->{'audio-path-linux'}   = $audioPath;
        $trackData->{'audio-path-windows'} = $audioWinPath;

        push @{$tracks}, $trackData;
    }

    my $price_tier = RPS::DB::Item::ServicePriceTier->LookupByProduct( service_id => $serviceID, product_id => $product->product_id );
    my $default_price_tier = RPS::DB::Item::ServicePriceTier->Lookup( service_id => $serviceID, default_tier => 1 );

    my $albumData = {};
    $albumData->{volume}           = \@volumes;
    $albumData->{'sell-bundled'}   = 'yes';
    $albumData->{'is-explicit'}    = $albumExplicitFlag;
    $albumData->{upc}              = $product->upc_ean;
    $albumData->{title}            = $album->title;
    $albumData->{'catalog-number'} = $album->catalog_number;
    $albumData->{'label'}          = $label->label_name;
    $albumData->{'release-date'}   = $product->release_date;
    $albumData->{'wholesale-price-tier'} = $price_tier->tier_code         if ($price_tier);
    $albumData->{'default-price-tier'}   = $default_price_tier->tier_code if ($default_price_tier);
    $albumData->{'cline'}                = $album->c_line;
    $albumData->{'pline'}                = $album->p_line;
    $albumData->{'genre'}                = \@genreNames;
    $albumData->{'genre-id'}             = $album->genre_primary_id;
    $albumData->{'genre-secondary'}      = \@genreNames_secondary;
    $albumData->{'genre-secondary-id'}   = $album->genre_secondary_id;
    $albumData->{'apple-album-id'}       = $appleAlbumID;

    $albumData->{'is-classical'} = $isComposerRequired;

    my $albumArtist = RPS::DB::Item::Artist->Lookup( artist_id => $album->artist_id );
    $albumData->{'display-artist'} = $albumArtist->name;

    $albumData->{'additional-artists'} = getAdditionalArtists( album_id => $albumID, service_id => $serviceID );

    # Get the image path
    #
    my $imageFile = MediaServe::DB::Item::AlbumFile->Lookup(
        album_id  => $album->album_id,
        file_type => MediaServe::DB::Item::AlbumFile::kFileTypeDistribution
    );
    assert( $imageFile, "Failed to find album image. Album ID: " . $album->album_id );

    my $mediaFile = MediaServe::DB::Item::MediaFile->Lookup( media_file_id => $imageFile->media_file_id );
    my $imagePath = MediaServe::Server::GetImagePath(
        mediaFileID => $imageFile->media_file_id,
        clientID    => Common::RSApp::GetClientID(),
        type        => 'linux'
    );
    my $imageWinPath = MediaServe::Server::GetImagePath(
        mediaFileID => $imageFile->media_file_id,
        clientID    => Common::RSApp::GetClientID(),
        type        => 'windows'
    );
    $albumData->{'image-file'}         = $mediaFile->filename;
    $albumData->{'image-path-linux'}   = $imagePath;
    $albumData->{'image-path-windows'} = $imageWinPath;

    # Build the territories XML
    #
    if ( scalar @territoryList ) {
        if ($territoryAllowedFlag) {
            $albumData->{'territories'}{'allowed'} = \@territoryList;
        } else {
            $albumData->{'territories'}{'denied'} = \@territoryList;
        }
    } else {
        $albumData->{'territories'} = undef;
    }

    my @albums;
    push @albums, $albumData;

    my %paramHash;
    $paramHash{album} = \@albums;

    # Now, we instantiate the XML object.
    #
    my $paramObj = Distribution::Job::Parameters->new( hash => \%paramHash );
    return $paramObj;
}

sub getAdditionalArtists {
    my %args = @_;
    my $hash;
    my $artistHash;
    my @result;

    my $serviceID = $args{service_id};

    assert($serviceID);

    if ( $args{album_id} ) {
        $artistHash = new RPS::Catalog::AlbumAdditionalArtistHash( albumID => $args{album_id}, serviceID => $serviceID );
    } elsif ( $args{track_id} ) {
        $artistHash = new RPS::Catalog::TrackAdditionalArtistHash( trackID => $args{track_id}, serviceID => $serviceID );
    }

    return unless ($artistHash);

    foreach my $key ( @{ $artistHash->getKeys() } ) {
        my $artist = $artistHash->getHash()->{$key};
        my $dbItem = RPS::DB::Item::ArtistRole->LookupWithMap( service_role => $artist->{Role}->Role(), service_id => $serviceID );

        $hash                               = {};
        $hash->{'artist-id'}                = $artist->ArtistID;
        $hash->{'display-artist'}           = $artist->Name;
        $hash->{'role'}->{'artist-role-id'} = $artist->{Role}->ArtistRoleID();
        $hash->{'role'}->{'name'}           = $artist->{Role}->Role();
        $hash->{'role'}->{'map'} = $dbItem->{service_role} if ($dbItem);

        push( @result, $hash );
    }

    return @result ? \@result : undef;
}

1;
