#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package RPS::Distribution::ParameterFactory;

use strict;

#use warnings;

use Data::Dumper;

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

use lib '/app/tools/rps/lib';
use RPS::DB::Item::Product;
use RPS::DB::Item::Album;
use RPS::DB::Item::Genre;
use RPS::DB::Item::ProductTrack;
use RPS::DB::Item::Track;
use RPS::DB::Item::Artist;
use RPS::DB::Item::Master;
use RPS::DB::Item::Song;
use RPS::DB::Item::Label;
use RPS::DB::Item::ProductDigital;
use RPS::DB::Item::ServicePriceTier;
use RPS::Catalog::TrackAdditionalArtistHash;
use RPS::Catalog::AlbumAdditionalArtistHash;

use lib '/app/tools/distribution/lib';
use Distribution::DB::Item::DistributionJob;
use Distribution::DB::Item::ProductDistribution;
use Distribution::Job::Parameters;
use Distribution::DB::Item::ProductServiceID;
use Distribution::DB::Item::ProductTrackServiceID;

use lib '/app/tools/mediaserve/lib';
use MediaServe::Server;
use MediaServe::DB::Item::ProductTrackFile;
use MediaServe::DB::Item::AlbumFile;

sub CreateDistributionParameters {
    my ($distProcessID) = @_;
    assert($distProcessID);

    # !!! Not sure this is the correct ID...
    # !!! Not even sure if this is really the interface we'll need.
    # !!! We will need a 'job' class, perhaps that can abstract away everything?
    #

    # This is just a quick sanity check.
    #
    my $jobData = Distribution::DB::Item::DistributionProcess->Lookup( distribution_process_id => $distProcessID );
    die "ERROR - distribution job id $distProcessID does not exist" unless $jobData;

    # So, there should just be _1_ service id.  I'm going to keep track of this, and
    # freak out if it changes...
    #
    my $serviceID;

    my @albums;

    # So, we're going to iterate over all the 'product_distribution' records with that dist_job_id.
    #
    my $productDistCollection = Distribution::DB::Item::ProductDistribution->GetAllByDistributionProcessID($distProcessID);
    while ( my $productDist = $productDistCollection->next() ) {
        if ( !defined $serviceID ) {
            $serviceID = $productDist->service_id;
        } elsif ( $productDist->service_id != $serviceID ) {
            die "ERROR - expected service_id $serviceID in this product_distribution record: " . Dumper($productDist);
        }

        my $productID = $productDist->product_id;
        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;
        $albumData->{'product-distribution-id'} = $productDist->product_distribution_id;

        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;
        }

        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;
