package Metadata::Importer;
use strict;

use lib '/app/tools/common/lib';
use Common::Log;
use Common::RSApp;
use Common::Assert;
use Data::Dumper;

use lib '/app/tools/metadata/lib';
use Metadata::Translator;
use Metadata::Validate::Harness;
use Metadata::DB::Item::ContentImport;
use Metadata::DB::Item::ContentImportStoredAlbum;

use Validate::Util qw(is_integer calculate_duration);
use Common::Util qw(trimspaces clean_name_catalog);

use lib '/app/tools/rps/lib';
use RPS::DB::Item::Artist;
use RPS::DB::Item::ArtistRole;
use RPS::DB::Item::AlbumAdditionalArtist;
use RPS::DB::Item::TrackAdditionalArtist;
use RPS::DB::Item::ArtistContractTermReserve;
use RPS::DB::Item::BonusTrack;
use RPS::DB::Item::LicenseReserve;
use RPS::DB::Item::MechanicalStatementItem;
use RPS::DB::Item::Label;
use RPS::DB::Item::Track;
use RPS::DB::Item::Album;
use RPS::DB::Item::Product;
use RPS::DB::Item::ProductTrack;
use RPS::DB::Item::ProductDigital;
use RPS::DB::Item::Master;
use RPS::DB::Item::Song;
use RPS::DB::Item::Composer;
use RPS::DB::Item::Genre;

use lib '/app/tools/distribution/lib';
use Distribution::DB::Item::ProductDistribution;
use Distribution::DB::Item::DistributionService;
use Distribution::DB::Item::DistributionService;
use Distribution::DB::Item::ServicePriceTier;
use Distribution::DB::Item::ProductServicePricing;

# Constructor
#

sub new {
    my ( $class, %args ) = @_;
    my $self = bless {}, $class;

    return $self->_init(%args);
}

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

    Common::Log::Debug("Initializing Metadata::Importer Object");
    Common::Log::Debug(
        sprintf(
            "ClientID: %s, Infile: %s, Handle: %s, Execute: %s, Automated: %s",
            $args{clientID}  ? $args{clientID} : "",
            $args{infile}    ? $args{infile}   : "<undef>",
            $args{fh}        ? $args{fh}       : "<undef>",
            $args{execute}   ? "Y"             : "N",
            $args{automated} ? "Y"             : "N"
        )
    );

    $self->{_clientID}  = $args{clientID};
    $self->{_execute}   = $args{execute};
    $self->{_infile}    = $args{infile};
    $self->{_fh}        = $args{fh};
    $self->{_automated} = $args{automated};

    return $self;
}

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

    return $self->{_errors} ? @{ $self->{_errors} } : undef;
}

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

    return undef unless ( $self->{_errors} );

    return "@{$self->{_errors}}";
}

sub import_file {
    my ( $self, %args ) = @_;
    assert( $self->{_infile} );

    my $translator = new Metadata::Translator( filename => $self->{_infile} );

    if ( $translator->error ) {
        my $version = $translator->version();

        if ( $version && ( $version->missingHeaders || $version->unknownHeaders ) ) {
            my $required_fields = "";
            my $unknown_fields  = "";

            if ( $version->unknownHeaders ) {
                $unknown_fields = sprintf(
                    "Invalid header%s: %s",
                    @{ $version->unknownHeaders } > 1 ? "s" : "",
                    join( ', ', @{ $version->unknownHeaders } )
                );
            }

            if ( $version->missingHeaders ) {
                $required_fields = sprintf(
                    "Required header%s: %s",
                    @{ $version->missingHeaders } > 1 ? "s" : "",
                    join( ', ', @{ $version->missingHeaders } )
                );
            }

            $self->{_errors} = [ sprintf( "Invalid header row: %s%s%s", $unknown_fields, $unknown_fields ? ", " : "", $required_fields ) ];

        } else {
            $self->{_errors} = [ $translator->error ];
        }

        Common::Log::Print( $self->error_str );

        return;
    }

    $self->_import( translator => $translator );
}

sub _get_parser {
    my $self = shift;
    my $parser;

    assert($self);

    return undef unless ( $self->{_infile} );

    if ( $self->{_infile} =~ /\.txt$/i ) {
        $parser = Metadata::Parser::Tab->open( fh => $self->{_fh}, infile => $self->{_infile} );
        $self->{_errors} = ["Failed to parse import file"] unless ($parser);
        return $parser;
    } elsif ( $self->{_infile} =~ /\.xls$/i ) {
        $parser = Metadata::Parser::Excel->open( fh => $self->{_fh}, infile => $self->{_infile} );
        $self->{_errors} = ["Failed to parse import file"] unless ($parser);
        return $parser;
    }

    $self->{_errors} = ["Unrecognized File Format"] unless ($parser);
    return $parser;
}

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

    my $validator = new Metadata::Validate::Harness( automated => $self->{_automated} );

    $validator->validate();
    $self->_set_timestamp("validate");

}

sub _import {
    my ( $self, %args ) = @_;
    assert( $self->{_infile} );
    assert( $args{translator} );

    my $translator = $args{translator};

    # If we have an import staged already the we can not continue
    if ( $self->is_staged() ) {
        $self->{_errors} = ["Another import is already staged.  Please reload the page."];
        return;
    }

    $self->_store_import($translator);
}

sub _store_import {
    my $self       = shift;
    my $translator = shift;
    assert($translator);

    my @rows = $translator->getAll();

    unless (@rows) {
        Common::Log::Debug("Document contains no data");
        $self->{_errors} = ["Document contains no data"];
        return;
    }

    $self->clean_import_tables();

    # Store import record
    my $contentDBObj = Metadata::DB::Item::ContentImport->Create();
    $contentDBObj->file_row_count( scalar @rows );
    $contentDBObj->save();

    Common::Log::Debug( " Content Import ID: " . $contentDBObj->content_import_id() );

    foreach my $row (@rows) {
        $self->_store_import_row( $row, $contentDBObj->content_import_id );
    }

    $self->_set_timestamp("import");
}

sub _store_import_row {
    my $self              = shift;
    my $row               = shift;
    my $content_import_id = shift;
    my @headers           = $row->getColumnNames;
    my $field;
    my $value;

    assert($row);
    assert($content_import_id);

    my $contentDataDBObj = Metadata::DB::Item::ContentImportData->Create();
    $contentDataDBObj->content_import_id($content_import_id);

    foreach $field (@headers) {
        $field =~ s/-/_/g;
        $field = lc($field);

        $value = $row->$field();

        # String leading and trailing semicolons from list fields
        if (   $field eq 'additional_album_artists'
            || $field eq 'additional_track_artists'
            || $field eq 'price_tiers' ) {

            $value =~ s/^;+// if ($value);
            $value =~ s/;+$// if ($value);
        }

        # strip leading and trailing blanks for all fields as well
        $value = trimspaces($value);

        $contentDataDBObj->$field($value);

        $value = "" unless ($value);
        Common::Log::Debug( "   Store: $field => " . $value );
    }

    $contentDataDBObj->save();
}

sub is_staged {
    my $self = shift;
    return Metadata::DB::Item::ContentImport->getStagedImport() ? 1 : undef;
}

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

    $self->_save_to_database(Validate::kStatusWarn);
    $self->_set_timestamp("store");
    Metadata::Parser->clean_import_tables();
}

sub reject {
    my ( $self, %args ) = @_;
    $self->_set_timestamp("reject");
    Metadata::Parser->clean_import_tables();
}

sub _set_timestamp {
    my ( $self, $action_type ) = @_;

    assert( $self, $action_type );

    my $dbo = Common::RSApp::GetClientDB;

    $dbo->DoCmd( "UPDATE content_import SET $action_type" . "_date = NOW() ORDER BY content_import_id desc LIMIT 1" );
}

sub _save_to_database {
    my $self = shift;
    my $error_level = shift || Validate::kStatusWarn;

    $error_level = Validate::kStatusWarn unless ( is_integer($error_level) );

    assert($self);
    Common::Log::Debug("   + Saving import to DB");

    my $stagedImport = Metadata::DB::Item::ContentImport->getStagedImport();

    unless ($stagedImport) {
        $self->{_errors} = ["Nothing staged found to import"];
        return;
    }

    my $contentImportID = $stagedImport->content_import_id;

    my $dbo = Common::RSApp::GetClientDB;

    my $base_sql = qq{
	    SELECT MAX(IF(type = 'track', status, NULL)) as track_status,
               album_status,
               SUM(override) as override_flag,
               content_import_data_status.content_import_data_status_id,
               content_import_data.*
        FROM content_import
             INNER JOIN content_import_data USING (content_import_id)
             LEFT JOIN content_import_data_status USING (content_import_data_id)
             LEFT JOIN (
                 SELECT content_import_data.content_import_data_id,
                        MAX(status) as album_status, catalog_no
                 FROM content_import_data_status
                      INNER JOIN content_import_data USING (content_import_data_id)
                 GROUP BY catalog_no ) as subq
                 	ON (content_import_data.catalog_no = subq.catalog_no )
        WHERE content_import.content_import_id = $contentImportID
        GROUP BY content_import_data.content_import_data_id };

    my $select_sql = qq{ SELECT * FROM ( $base_sql ) as q
	    WHERE ( (track_status <= $error_level OR track_status IS NULL) AND
	            (album_status <= $error_level OR album_status IS NULL) ) OR
	          override_flag > 0 };

    my $sth = $dbo->DoCmd($select_sql);

    my $row;

    Common::Log::Debug("$select_sql");

    while ( $row = $sth->fetchrow_hashref() ) {
        Common::Log::Debug(
            sprintf(
                "CID: %s, Track Status: %s, Album Status: %s",
                $row->{content_import_data_id},
                $row->{track_status} ? $row->{track_status} : "undef",
                $row->{album_status} ? $row->{album_status} : "undef"
            )
        );

        $self->_save_track_to_db($row)
          if ( ( !defined( $row->{track_status} ) && !defined( $row->{album_status} ) )
            || ( defined( $row->{track_status} ) && $row->{track_status} <= $error_level )
            || ( defined( $row->{album_status} ) && $row->{album_sGtatus} <= $error_level )
            || $row->{override} );
    }

    Common::Log::Debug("   + Renumbering Digital Track Products");

    if ( $self->{_digitalProducts} ) {
        foreach ( keys( %{ $self->{_digitalProducts} } ) ) {
            Common::Log::Debug("       - Renumbering product_id $_");
            $self->_renumberDigitalProductTracks($_);
        }
    }

    Common::Log::Debug("   + Clear staged import data");

    my $delete_sql = qq{
		DELETE content_import_data_status.*, content_import_data.* FROM ( $base_sql ) as q
    		LEFT JOIN content_import_data ON (q.content_import_data_id = content_import_data.content_import_data_id)
    		LEFT JOIN content_import_data_status ON (content_import_data.content_import_data_id = content_import_data_status.content_import_data_id)
        WHERE ( (track_status <= $error_level OR track_status IS NULL) AND
                (album_status <= $error_level OR album_status IS NULL) ) OR
              override_flag > 0 };

    Common::Log::Debug("$delete_sql");

    $sth = $dbo->DoCmd($delete_sql);

}

sub _save_track_to_db {
    my $self = shift;
    my $row  = shift;

    assert( $self, $row );

    Common::Log::Debug(
        sprintf(
            "   + Storing Catalog Number: Album: %s, Track: %s, Label: %s",
            $row->{catalog_no}  ? $row->{catalog_no}  : "undef",
            $row->{album_title} ? $row->{album_title} : "undef",
            $row->{track_title} ? $row->{track_title} : "undef",
            $row->{label_name}  ? $row->{label_name}  : "undef"
        )
    );

    # Does this label exist already?
    #
    my $labelName = $row->{label_name};
    my $labelDBItem = RPS::DB::Item::Label->Lookup( label_name => $labelName );
    if ( !$labelDBItem ) {
        $labelDBItem = RPS::DB::Item::Label->Create(
            label_name       => $labelName,
            label_name_clean => clean_name_catalog($labelName),
        );
        $labelDBItem->save();
    }
    my $labelID = $labelDBItem->label_id;

    my $artistID = $self->_createArtist( $row->{album_artist} );

    my $primaryGenre = RPS::DB::Item::Genre->Lookup( genre_name => $row->{primary_genre} )
      if ( $row->{primary_genre} );

    my $secondaryGenre = RPS::DB::Item::Genre->Lookup( genre_name => $row->{secondary_genre} )
      if ( $row->{secondary_genre} );

    my $Album;

    if ( $self->{_automated} ) {
        $Album = RPS::DB::Item::Album->Lookup(
            catalog_number => $row->{catalog_no},
            title          => $row->{album_title},
            artist_id      => $artistID,
            label_id       => $labelID,
            status         => 1,                     # 1=active
        );
    } else {
        $Album = RPS::DB::Item::Album->Lookup( catalog_number => $row->{catalog_no} );
    }

    unless ($Album) {
        $Album = RPS::DB::Item::Album->Create(
            catalog_number     => $row->{catalog_no},
            title              => $row->{album_title},
            title_clean        => clean_name_catalog( $row->{album_title} ),
            artist_id          => $artistID,
            label_id           => $labelID,
            genre_primary_id   => $primaryGenre ? $primaryGenre->genre_id() : undef,
            genre_secondary_id => $secondaryGenre ? $secondaryGenre->genre_id() : undef,
            c_line             => $row->{c_line},
            p_line             => $row->{p_line},
            custom_1           => $row->{album_custom_1},
            custom_2           => $row->{album_custom_2},
            custom_3           => $row->{album_custom_3},
            client_album_id    => $row->{client_album_id},
            status             => 1,                                                       # 1=active
        );

        $Album->save();

        my $stagedUpdate = Metadata::DB::Item::ContentImport->getStagedImport();
        my $CMStored     = Metadata::DB::Item::ContentImportStoredAlbum->Create(
            content_import_id => $stagedUpdate->content_import_id(),
            album_id          => $Album->album_id
        );

        $CMStored->save();

        $self->_createAdditionalArtists( album_id => $Album->album_id, artists => $row->{additional_album_artists} );
    }

    my $albumID = $Album->album_id;
    my $product_code;

    # Now create a corresponding digital product (for the album).
    my ( $albumDigitalProductID, $albumCDProductID, $albumVinylProductID, $albumDVDProductID );
    if ( $row->{digital_upc} ) {
        $albumDigitalProductID = RPS::DB::Item::Product->GetProductIDByUPC(
            upc             => $row->{digital_upc},
            product_type_id => RPS::DB::Item::Product::kProductTypeDigital,
            album_id        => $albumID
        );

        $product_code = $row->{digital_product_id};

        unless ($albumDigitalProductID) {
            my $newDigProduct = RPS::DB::Item::Product->Create(
                title             => $row->{album_title},
                title_clean       => clean_name_catalog( $row->{album_title} ),
                asset_id          => $albumID,
                upc_ean           => $row->{digital_upc},
                release_date      => $row->{digital_release_date},
                product_code      => $product_code,
                product_type_id   => RPS::DB::Item::Product::kProductTypeDigital,    # 3 == digital
                product_status_id => 1,                                              # 1 == active
            );
            $newDigProduct->save();

            my $territories = $row->{territories_allowed} ? $row->{territories_allowed} : $row->{territories_denied};
            my $territory_type = "";
            $territory_type = "A"
              if ( $row->{territories_allowed} && length( $row->{territories_allowed} ) );

            $territory_type = "D"
              if ( $row->{territories_denied} && length( $row->{territories_denied} ) );

            my $dist_allow = $row->{cleared_for_distribution};
            $dist_allow = $dist_allow && $dist_allow =~ /^n$/i ? 0 : 1;

            my $newProductDigital = RPS::DB::Item::ProductDigital->Create(
                product_id       => $newDigProduct->product_id,
                territories_list => $territories,
                territories_flag => $territory_type,
                dist_allow       => $dist_allow,
            );
            $newProductDigital->save();

            $albumDigitalProductID = $newDigProduct->product_id;

            $self->_createProductDistribution( $newDigProduct->product_id );
            $self->_createProductServicePricing( $newDigProduct->product_id, $row->{price_tiers} );
        }
    }

    if ( $row->{cd_upc} ) {
        $albumCDProductID = RPS::DB::Item::Product->GetProductIDByAlbumID(
            album_id        => $albumID,
            product_type_id => RPS::DB::Item::Product::kProductTypeCD
        );

        $product_code = $row->{cd_product_id};

        unless ($albumCDProductID) {
            my $newPhysProduct = RPS::DB::Item::Product->Create(
                title             => $row->{album_title},
                title_clean       => clean_name_catalog( $row->{album_title} ),
                asset_id          => $albumID,
                upc_ean           => $row->{cd_upc},
                release_date      => $row->{cd_release_date},
                product_code      => $product_code,
                product_type_id   => RPS::DB::Item::Product::kProductTypeCD,      # 2 == cd
                product_status_id => 1,                                           # 1 == active
            );
            $newPhysProduct->save();
            $albumCDProductID = $newPhysProduct->product_id;
        }
    }

    if ( $row->{vinyl_upc} ) {
        $albumVinylProductID = RPS::DB::Item::Product->GetProductIDByAlbumID(
            album_id        => $albumID,
            product_type_id => RPS::DB::Item::Product::kProductTypeLP
        );

        $product_code = $row->{vinyl_product_id};

        unless ($albumVinylProductID) {
            my $newPhysProduct = RPS::DB::Item::Product->Create(
                title             => $row->{album_title},
                title_clean       => clean_name_catalog( $row->{album_title} ),
                asset_id          => $albumID,
                upc_ean           => $row->{vinyl_upc},
                release_date      => $row->{vinyl_release_date},
                product_code      => $product_code,
                product_type_id   => RPS::DB::Item::Product::kProductTypeLP,
                product_status_id => 1,                                           # 1 == active
            );
            $newPhysProduct->save();
            $albumVinylProductID = $newPhysProduct->product_id;
        }
    }

    if ( $row->{dvd_upc} ) {
        $albumDVDProductID = RPS::DB::Item::Product->GetProductIDByAlbumID(
            album_id        => $albumID,
            product_type_id => RPS::DB::Item::Product::kProductTypeDVD
        );

        $product_code = $row->{dvd_product_id};

        unless ($albumDVDProductID) {
            my $newPhysProduct = RPS::DB::Item::Product->Create(
                title             => $row->{album_title},
                title_clean       => clean_name_catalog( $row->{album_title} ),
                asset_id          => $albumID,
                upc_ean           => $row->{dvd_upc},
                release_date      => $row->{dvd_release_date},
                product_code      => $product_code,
                product_type_id   => RPS::DB::Item::Product::kProductTypeDVD,
                product_status_id => 1,                                           # 1 == active
                     # product_price_id => 1,     # 1 == full (the default) # don't set this at all -jff-
            );
            $newPhysProduct->save();
            $albumDVDProductID = $newPhysProduct->product_id;
        }
    }

    my $trackArtistID = $self->_createArtist( $row->{track_artist} );

    my $composerDBItem;
    if ( $row->{track_composer} && length( $row->{track_composer} ) ) {

        $composerDBItem = RPS::DB::Item::Composer->Lookup( name => $row->{track_composer} );

        if ( !$composerDBItem ) {
            $composerDBItem = RPS::DB::Item::Composer->Create( name => $row->{track_composer}, );
            $composerDBItem->save();
        }
    }

    my $composerID = $composerDBItem->composer_id
      if ($composerDBItem);

    #
    # Now create the master and song if necessary
    #

    my $Song;
    if ( $self->{_automated} ) {
        $Song = RPS::DB::Item::Song->Lookup( title => $row->{track_title}, composer_id => $composerID );
    }

    unless ($Song) {
        $Song = RPS::DB::Item::Song->Create(
            title       => $row->{track_title},
            composer_id => $composerID,
        );
        $Song->save();
    }

    my $trackSongID = $Song->song_id;

    my $Master;
    if ( $self->{_automated} ) {
        $Master = RPS::DB::Item::Master->Lookup(
            song_id   => $trackSongID,
            title     => $row->{track_title},
            artist_id => $trackArtistID,
            isrc      => $row->{isrc},
            duration  => calculate_duration(
                minutes => $row->{track_minutes},
                seconds => $row->{track_seconds}
            ),
        );
    }

    unless ($Master) {
        $Master = RPS::DB::Item::Master->Create(
            song_id   => $trackSongID,
            title     => $row->{track_title},
            artist_id => $trackArtistID,
            isrc      => $row->{isrc},
            duration  => calculate_duration(
                minutes => $row->{track_minutes},
                seconds => $row->{track_seconds}
            ),
        );
        $Master->save();
    }
    my $trackMasterID = $Master->master_id;

    my $media_type = $row->{media_type};

    # Nobody can decide how the metadata should store media type, either 1 or 2
    # A and V.  A = 1, V = 1.
    # So for now if the media type is 'A' we will convert it to 1 and 'V' to 2
    $media_type = 1 if ( $media_type && $media_type =~ /^a/i );
    $media_type = 2 if ( $media_type && $media_type =~ /^v/i );

    my $track_number;
    my $track_order;
    my $disc_number = 1;

    if    ( $row->{digital_disc_number} ) { $disc_number = $row->{digital_disc_number} }
    elsif ( $row->{cd_disc_number} )      { $disc_number = $row->{cd_disc_number} }
    elsif ( $row->{dvd_disc_number} )     { $disc_number = $row->{dvd_disc_number} }
    elsif ( $row->{vinyl_disc_number} )   { $disc_number = $row->{vinyl_disc_number} }

    if    ( $row->{digital_track_number} ) { $track_number = $row->{digital_track_number} }
    elsif ( $row->{cd_track_number} )      { $track_number = $row->{cd_track_number} }
    elsif ( $row->{dvd_track_number} )     { $track_number = $row->{dvd_track_number} }
    elsif ( $row->{vinyl_track_number} )   { $track_number = $row->{vinyl_track_number} }

    #$track_order = $disc_number * $track_number;

    #
    # Per FB12898, the track ordering should be sequential
    #
    my $dbo         = Common::RSApp::GetClientDB;
    my $sql         = "SELECT MAX(track_order) FROM track WHERE album_id=$albumID";
    my $sth         = $dbo->DoCmd($sql);
    my $track_order = 1;
    if ( $sth->rows > 0 ) {
        my ($num) = $sth->fetchrow_array();
        $track_order = $num + 1;
    }

    my $Track;
    if ( $self->{_automated} ) {
        $Track = RPS::DB::Item::Track->Lookup(
            title             => $row->{track_title},
            title_clean       => clean_name_catalog( $row->{track_title} ),
            album_id          => $albumID,
            artist_id         => $trackArtistID,
            custom_1          => $row->{track_custom_1},
            custom_2          => $row->{track_custom_2},
            custom_3          => $row->{track_custom_3},
            parental_advisory => $row->{explicit} || 'N',
            client_track_id   => $row->{client_track_id},
            media_type        => $media_type || 1,
            master_id         => $trackMasterID,
        );
    }

    unless ($Track) {
        $Track = RPS::DB::Item::Track->Create(
            title             => $row->{track_title},
            title_clean       => clean_name_catalog( $row->{track_title} ),
            album_id          => $albumID,
            artist_id         => $trackArtistID,
            track_order       => $track_order,
            custom_1          => $row->{track_custom_1},
            custom_2          => $row->{track_custom_2},
            custom_3          => $row->{track_custom_3},
            parental_advisory => $row->{explicit},
            client_track_id   => $row->{client_track_id},
            media_type        => $media_type,
            master_id         => $trackMasterID,
        );
        $Track->save();

        $self->_createAdditionalArtists( track_id => $Track->track_id, artists => $row->{additional_track_artists} );
    }

    my $trackID = $Track->track_id;

    # Now create a corresponding digital product for this track.

    # Only create a digital product track if exclude digital is set to 'n'
    if ( $albumDigitalProductID
        && ( !defined( $row->{exclude_digitally} ) || $row->{exclude_digitally} =~ /n/i ) ) {
        my $newProduct = RPS::DB::Item::Product->Create(
            asset_id          => $trackID,
            product_type_id   => RPS::DB::Item::Product::kProductTypeDigitalTrack,    # 4 == digital track
            product_status_id => 1,                                                   # 1 == active
            parent_product_id => $albumDigitalProductID,
        );
        $newProduct->save();
    }

    # Only create a digital product track if exclude digital is set
    if ( $albumDigitalProductID
        && ( !defined( $row->{exclude_digitally} ) || $row->{exclude_digitally} =~ /n/i ) ) {

        my $albumOnly = 1
          if ( $row->{album_purchase_only} && $row->{album_purchase_only} =~ /y/i );

        my $digProductTrack = RPS::DB::Item::ProductTrack->Create(
            product_id  => $albumDigitalProductID,
            track_id    => $trackID,
            disc_number => $row->{digital_disc_number},
            disc_track  => $row->{digital_track_number},
            album_only  => $albumOnly
        );
        $digProductTrack->save();

        $self->{_digitalProducts} = {} unless ( $self->{_digitalProducts} );
        $self->{_digitalProducts}->{$albumDigitalProductID} = 1;
    }

    if ($albumCDProductID) {
        my $physProductTrack = RPS::DB::Item::ProductTrack->Create(
            product_id  => $albumCDProductID,
            track_id    => $trackID,
            disc_number => $row->{cd_disc_number},
            disc_track  => $row->{cd_track_number},
        );
        $physProductTrack->save();
    }

    if ($albumVinylProductID) {
        my $physProductTrack = RPS::DB::Item::ProductTrack->Create(
            product_id  => $albumVinylProductID,
            track_id    => $trackID,
            disc_number => $row->{vinyl_disc_number},
            disc_track  => $row->{vinyl_track_number},
        );
        $physProductTrack->save();
    }

    if ($albumDVDProductID) {
        my $physProductTrack = RPS::DB::Item::ProductTrack->Create(
            product_id  => $albumDVDProductID,
            track_id    => $trackID,
            disc_number => $row->{dvd_disc_number},
            disc_track  => $row->{dvd_track_number},
        );
        $physProductTrack->save();
    }
}

sub _createArtist {
    my $self       = shift;
    my $artistName = shift;

    assert($artistName);

    # Does this artist exist already?
    #
    my $artistDBItem = RPS::DB::Item::Artist->Lookup( name => $artistName );

    if ( !$artistDBItem ) {
        $artistDBItem = RPS::DB::Item::Artist->Create(
            name       => $artistName,
            name_clean => clean_name_catalog($artistName),
        );
        $artistDBItem->save();
    }
    return $artistDBItem->artist_id;
}

sub _createProductServicePricing {
    my $self       = shift;
    my $dProductID = shift;
    my $tiers      = shift || return;

    Common::Log::Debug("Tier String: $tiers");

    my %priceTiers;
    my @values = split( /\s*[=;]\s*/, $tiers );

    if ( @values % 2 != 0 ) {
        die("Uneven list for price tiers. ");
    }

    for ( my $i = 0 ; $i < @values - 1 ; $i += 2 ) {
        Common::Log::Debug("KEY: $values[$i] VALUE: $values[$i+1]");
        $values[$i] =~ s/^\s+//;
        $values[$i] =~ s/\s+$//;
        $values[ $i + 1 ] =~ s/^\s+//;
        $values[ $i + 1 ] =~ s/\s+$//;

        my $key = lc( $values[$i] );
        $priceTiers{$key} = $values[ $i + 1 ];
    }

    Common::Log::Debug Dumper( \%priceTiers );

    foreach ( keys(%priceTiers) ) {
        my $service = Distribution::DB::Item::DistributionService->Lookup( service_name => $_ )
          || die "Service not found";
        my $service_tier =
          Distribution::DB::Item::ServicePriceTier->Lookup( service_id => $service->service_id, tier_name => $priceTiers{$_} )
          || die "Tier not found";
        my $tier = Distribution::DB::Item::ProductServicePricing->Create();

        $tier->service_id( $service->service_id );
        $tier->product_id($dProductID);
        $tier->service_price_tier_id( $service_tier->service_price_tier_id );
        $tier->save();
    }
}

sub _createAdditionalArtists {
    my $self    = shift;
    my %args    = @_;
    my $albumID = $args{album_id};
    my $trackID = $args{track_id};
    my $artists = $args{artists} || return;
    my $artistDB;

    assert($artists);
    assert( $trackID || $albumID );

    my @values = split( /\s*[=;]\s*/, $artists );

    if ( @values % 2 != 0 ) {
        die("Uneven list for additional artists. ");
    }

    for ( my $i = 0 ; $i < @values - 1 ; $i += 2 ) {
        my $role     = RPS::DB::Item::ArtistRole->Lookup( role => $values[ $i + 1 ] ) || die;
        my $roleID   = $role->artist_role_id;
        my $artistID = $self->_createArtist( $values[$i] );

        if ($albumID) {
            next if RPS::DB::Item::AlbumAdditionalArtist->Lookup(
                album_id       => $albumID,
                artist_id      => $artistID,
                artist_role_id => $roleID
            );
            $artistDB = RPS::DB::Item::AlbumAdditionalArtist->Create();
            $artistDB->album_id($albumID);
        } else {
            next if RPS::DB::Item::TrackAdditionalArtist->Lookup(
                track_id       => $trackID,
                artist_id      => $artistID,
                artist_role_id => $roleID
            );
            $artistDB = RPS::DB::Item::TrackAdditionalArtist->Create();
            $artistDB->track_id($trackID);
        }

        $artistDB->artist_id($artistID);
        $artistDB->artist_role_id($roleID);
        $artistDB->save();
    }
}

sub _createProductDistribution {
    my $self       = shift;
    my $dProductID = shift;
    my $client_id  = Common::RSApp::GetClientID();

    return unless $dProductID;

    my $services = Distribution::DB::Item::DistributionService->GetAllClientServices($client_id);

    while ( $services->hasNext ) {
        my $service = $services->next;

        if ( $service->{configured} ) {
            my $pDistribution = Distribution::DB::Item::ProductDistribution->Create();

            $pDistribution->product_id($dProductID);
            $pDistribution->service_id( $service->service_id );

            $pDistribution->save();
        }
    }
}

sub _renumberDigitalProductTracks {
    my $self = shift;
    my $product_id = shift || return;
    my %counter;
    my $disc_number;

    my $tracks = RPS::DB::Item::ProductTrack->GetTracksByProductID($product_id);

    while ( $tracks->hasNext() ) {
        my $track = $tracks->next();
        $disc_number = $track->disc_number ? $track->disc_number : 1;
        $counter{$disc_number} = $counter{$disc_number} ? $counter{$disc_number} + 1 : 1;

        Common::Log::Debug( "Counter: $counter{$disc_number} Track: " . $track->disc_track );

        if ( $track->disc_track != $counter{$disc_number} ) {
            $track->disc_track( $counter{$disc_number} );
            $track->save();
        }

    }
}

sub clean_import_tables {
    my $db_field;

    # Clear out the DB first
    my $dbo = Common::RSApp::GetClientDB();

    $dbo->DoCmd("DELETE FROM content_import_data_status");
    $dbo->DoCmd("DELETE FROM content_import_data");
}

1;
