use strict;
use lib '/app/tools/common/lib';
use Common::RSApp;
use Common::RSDB;
use Common::DB::Item::ClientCMIDMap;

use Data::Dumper;

use lib '/app/tools/rps/lib';
use RPS::DB::Item::Album;

use AllMetadata;
use constant kCMClientID => 112;

use constant client_id       => 0;
use constant album_name      => 1;
use constant album_artist    => 2;
use constant album_artist_id => 3;
use constant label_name      => 4;
use constant label_id        => 5;
use constant catalog_id      => 6;
use constant upc             => 7;
use constant album_id        => 8;
use constant client_album_id => 9;
use constant release_date    => 10;
use constant upc_alt         => 11;
use constant album_custom_1  => 12;
use constant album_custom_2  => 13;
use constant album_custom_3  => 14;
use constant track_name      => 15;
use constant disc_no         => 16;
use constant disc_name       => 17;
use constant track_no        => 18;
use constant track_minutes   => 19;
use constant track_seconds   => 20;
use constant track_artist    => 21;
use constant track_artist_id => 22;
use constant isrc            => 23;
use constant track_id        => 24;
use constant client_track_id => 25;
use constant genre           => 26;
use constant track_custom_1  => 27;
use constant track_custom_2  => 28;
use constant track_custom_3  => 29;
use constant master_id       => 30;
use constant song_id         => 31;
use constant song_title      => 32;
use constant composer_id     => 33;
use constant composer_name   => 34;
use constant kNumFields      => 35;

my %gIndexToFieldMap = (
    client_id()       => 'client_id',
    album_name()      => 'album_name',
    album_artist()    => 'album_artist',
    album_artist_id() => 'album_artist_id',
    label_name()      => 'label_name',
    label_id()        => 'label_id',
    catalog_id()      => 'catalog_id',
    upc()             => 'upc',
    album_id()        => 'album_id',
    client_album_id() => 'client_album_id',
    release_date()    => 'release_date',
    upc_alt()         => 'upc_alt',
    album_custom_1()  => 'album_custom_1',
    album_custom_2()  => 'album_custom_2',
    album_custom_3()  => 'album_custom_3',
    track_name()      => 'track_name',
    disc_no()         => 'disc_no',
    disc_name()       => 'disc_name',
    track_no()        => 'track_no',
    track_minutes()   => 'track_minutes',
    track_seconds()   => 'track_seconds',
    track_artist()    => 'track_artist',
    track_artist_id() => 'track_artist_id',
    isrc()            => 'isrc',
    track_id()        => 'track_id',
    client_track_id() => 'client_track_id',
    genre()           => 'genre',
    track_custom_1()  => 'track_custom_1',
    track_custom_2()  => 'track_custom_2',
    track_custom_3()  => 'track_custom_3',
    master_id()       => 'master_id',
    song_id()         => 'song_id',
    song_title()      => 'song_title',
    composer_id()     => 'composer_id',
    composer_name()   => 'composer_name',
);

my $singleton = Common::RSApp->new( clientID => kCMClientID );

# Go through all the metadata in the dump table, and
# see if I can find matches.
#

my $dbo = Common::RSApp::GetClientDB();
my $dbh = $dbo->DBH;

my @match;
my @nomatch;
my @multiple;

my $linenum = 1;
while ( my $line = <STDIN> ) {
    print STDERR "$linenum\n";
    chop $line;

    # Parse the line into the proper chunks.
    #
    my @bits = split( /\t/, $line );

    # See if I can find all the matching stuff in one shot.
    # !!! What I'll do is add _all_ the fields to the @where array, then
    # !!! try to match that.  If I don't get a match, I'll start removing
    # !!! fields until I do, or until I run out of fields that I feel comfortable
    # !!! removing, or until we hit a multi-match.
    #
    my @where;
    push @where, 'album_name = ' . $dbo->DBQuote( $bits[album_name] );
    push @where, 'album_artist = ' . $dbo->DBQuote( $bits[album_artist] );
    push @where, 'track_name = ' . $dbo->DBQuote( $bits[track_name] );
    push @where, 'track_artist = ' . $dbo->DBQuote( $bits[track_artist] );
    push @where, 'release_date= ' . $dbo->DBQuote( $bits[release_date] );
    push @where, 'catalog_id = ' . $dbo->DBQuote( $bits[catalog_id] );
    push @where, 'upc = ' . $dbo->DBQuote( $bits[upc] );
    push @where, 'isrc = ' . $dbo->DBQuote( $bits[isrc] );
    push @where, 'genre= ' . $dbo->DBQuote( $bits[genre] );
    push @where, 'label_name = ' . $dbo->DBQuote( $bits[label_name] );
    push @where, 'client_album_id= ' . $dbo->DBQuote( $bits[client_album_id] );
    push @where, 'upc_alt = ' . $dbo->DBQuote( $bits[upc_alt] );
    push @where, 'song_title = ' . $dbo->DBQuote( $bits[song_title] );
    push @where, 'composer_name= ' . $dbo->DBQuote( $bits[composer_name] );
    push @where, 'track_minutes= ' . $dbo->DBQuote( $bits[track_minutes] );
    push @where, 'track_seconds= ' . $dbo->DBQuote( $bits[track_seconds] );
    push @where, 'disc_no = ' . $dbo->DBQuote( $bits[disc_no] );
    push @where, 'disc_name = ' . $dbo->DBQuote( $bits[disc_name] );
    push @where, 'track_no= ' . $dbo->DBQuote( $bits[track_no] );
    push @where, 'album_custom_1= ' . $dbo->DBQuote( $bits[album_custom_1] );
    push @where, 'album_custom_2= ' . $dbo->DBQuote( $bits[album_custom_2] );
    push @where, 'album_custom_3= ' . $dbo->DBQuote( $bits[album_custom_3] );
    push @where, 'track_custom_1= ' . $dbo->DBQuote( $bits[track_custom_1] );
    push @where, 'track_custom_2= ' . $dbo->DBQuote( $bits[track_custom_2] );
    push @where, 'track_custom_3= ' . $dbo->DBQuote( $bits[track_custom_3] );

    # Keep trying to match until we succeed, removing fields from the back of the array.
    # If we only have the first 4 fields, left, then we've failed.
    while ( scalar @where > 1 ) {
        my $sql = "SELECT * FROM zzall_metadata WHERE " . join( ' AND ', @where );
        my $collection = AllMetadata->GetAll($sql);
        if ( 1 == $collection->size() ) {

            # !!! What do I really need to make the entry?
            push @match, $linenum;
            my $matchedItem = $collection->next();
            makeMapEntry( $matchedItem, \@bits );
            last;
        } elsif ( 1 < $collection->size() ) {

            # !!! Let's see if I can winnow this down.
            #
            my @possible;
            my $bestSoFar = 0;
            my $bestIndex = undef;
            my $i         = 0;
            while ( my $matched = $collection->next() ) {

                # Count up how many fields actually match.
                #
                my $count = 0;
                for ( my $f = 0 ; $f < kNumFields ; $f++ ) {

                    # Skip some of these fields.
                    #
                    next
                      if ( album_id == $f
                        || track_id == $f
                        || album_artist_id == $f
                        || track_artist_id == $f
                        || label_id == $f
                        || song_id == $f
                        || composer_id == $f
                        || master_id == $f );

                    my $fieldname = $gIndexToFieldMap{$f};
                    if ( $matched->$fieldname eq $bits[$f] ) {
                        $count++;
                    }
                }

                if ( $count > $bestSoFar ) {
                    $bestSoFar = $count;
                    $bestIndex = $i;
                } elsif ( $count == $bestSoFar ) {

                    # if two have identical counts, then we don't have a winner...
                    #
                    $bestIndex = undef;
                }
                push @possible, $matched;
                $i++;
            }

            if ( defined $bestIndex ) {

                # We have a winner!
                # !!! This will change to actually make the map entry.
                #
                my $matchedItem = $possible[$bestIndex];
                makeMapEntry( $matchedItem, \@bits );
                push @match, $linenum;
                last;
            }
            my $matchline = "$linenum\t$line\n---possibles---\n";
            foreach my $matched (@possible) {
                $matchline .= "\t" . $matched->client_id;
                $matchline .= "\t" . $matched->album_name;
                $matchline .= "\t" . $matched->album_artist;
                $matchline .= "\t" . $matched->album_artist_id;
                $matchline .= "\t" . $matched->label_name;
                $matchline .= "\t" . $matched->label_id;
                $matchline .= "\t" . $matched->catalog_id;
                $matchline .= "\t" . $matched->upc;
                $matchline .= "\t" . $matched->album_id;
                $matchline .= "\t" . $matched->client_album_id;
                $matchline .= "\t" . $matched->release_date;
                $matchline .= "\t" . $matched->upc_alt;
                $matchline .= "\t" . $matched->album_custom_1;
                $matchline .= "\t" . $matched->album_custom_2;
                $matchline .= "\t" . $matched->album_custom_3;
                $matchline .= "\t" . $matched->track_name;
                $matchline .= "\t" . $matched->disc_no;
                $matchline .= "\t" . $matched->disc_name;
                $matchline .= "\t" . $matched->track_no;
                $matchline .= "\t" . $matched->track_minutes;
                $matchline .= "\t" . $matched->track_seconds;
                $matchline .= "\t" . $matched->track_artist;
                $matchline .= "\t" . $matched->track_artist_id;
                $matchline .= "\t" . $matched->isrc;
                $matchline .= "\t" . $matched->track_id;
                $matchline .= "\t" . $matched->client_track_id;
                $matchline .= "\t" . $matched->genre;
                $matchline .= "\t" . $matched->track_custom_1;
                $matchline .= "\t" . $matched->track_custom_2;
                $matchline .= "\t" . $matched->track_custom_3;
                $matchline .= "\t" . $matched->master_id;
                $matchline .= "\t" . $matched->song_id;
                $matchline .= "\t" . $matched->song_title;
                $matchline .= "\t" . $matched->composer_id;
                $matchline .= "\t" . $matched->composer_name;
                $matchline .= "\n";
            }
            push @multiple, $matchline;
            last;
        }

        # We didn't match any - take away a field from the where clause and try again.
        #
        pop @where;
    }

    if ( scalar @where < 2 ) {
        push @nomatch, "$linenum\t$line";
    }

    $linenum++;
}

print "match: " . scalar @match . "\n";
print "\nno match: " . scalar @nomatch . "\n";
foreach my $notmatched (@nomatch) {
    print "$notmatched\n";
}
print "\nmultiple: " . scalar @multiple . "\n";
foreach my $multimatch (@multiple) {
    print "$multimatch\n";
}

sub makeMapEntry {
    my ( $matchedItem, $bits ) = @_;

    # bits is the parsed line with the cm data
    # matchedItem is the db object with the client data
    #
    my $clientID = $matchedItem->client_id;

    addFieldToMap( $clientID, $bits->[album_id],        $matchedItem->album_id,        'album_id' );
    addFieldToMap( $clientID, $bits->[track_id],        $matchedItem->track_id,        'track_id' );
    addFieldToMap( $clientID, $bits->[album_artist_id], $matchedItem->album_artist_id, 'artist_id' );
    addFieldToMap( $clientID, $bits->[track_artist_id], $matchedItem->track_artist_id, 'artist_id' );
    addFieldToMap( $clientID, $bits->[label_id],        $matchedItem->label_id,        'label_id' );
    addFieldToMap( $clientID, $bits->[master_id],       $matchedItem->master_id,       'master_id' );
    addFieldToMap( $clientID, $bits->[song_id],         $matchedItem->song_id,         'song_id' );
    addFieldToMap( $clientID, $bits->[composer_id],     $matchedItem->composer_id,     'composer_id' );
}

sub addFieldToMap {
    my ( $clientID, $cmSiteID, $clientSiteID, $idType ) = @_;

    return if ( !$cmSiteID && !$clientSiteID );

    # We'll do this initial lookup with just the client site id.
    # That way we can make sure we don't have wonky data
    #
    my $currentItem = Common::DB::Item::ClientCMIDMap->Lookup(
        id_type        => $idType,
        client_id      => $clientID,
        client_site_id => $clientSiteID,

        #        cm_site_id => $cmAlbumID,
    );
    if ($currentItem) {
        if ( $currentItem->cm_site_id != $cmSiteID ) {
            die "ERROR! Already have a map entry!: client $clientID, $idType client site id $clientSiteID, current cm id "
              . $currentItem->cm_site_id
              . " != $cmSiteID\n";
        }
    } else {

        # Make a new entry
        #
        my $newItem = Common::DB::Item::ClientCMIDMap->Create(
            client_id      => $clientID,
            client_site_id => $clientSiteID,
            cm_site_id     => $cmSiteID,
            id_type        => $idType,
        );
        $newItem->save();
    }
}
