package MusicBrainz;

use strict;
use warnings;

our @ISA    = qw{Exporter};
our @EXPORT = qw{get_musicbrainz_info};

#use WebService::MusicBrainz;
use LWP;
use XML::XPath;
use XML::XPath::XMLParser;

sub lookup_release {
    my ($discid) = @_;
    my $ua = LWP::UserAgent->new;

    #my $uri = URI->new('http://musicbrainz.org/ws/1/release/');
    #$uri->query_form(type => 'xml', discid => $discid);
    my $uri = URI->new("http://musicbrainz.org/ws/2/discid/$discid");
    $uri->query_form(inc => 'artists+labels+recordings+release-groups+artist-credits');

    my $res = $ua->get($uri);
    # pause for a second, so we don't run afoul of the MusicBrainz API TOS
    sleep 1;

    warn $res->status_line, "\n" if $res->code != 200;
    return if $res->code >= 400;
    #TODO: if we get a 5xx error, retry?

    return $res->decoded_content;
}

sub get_musicbrainz_info {
    my ($discid) = @_;
    my %info;

    $info{MBZ_DISCID} = $discid;

    my $xpath = XML::XPath->new();
    my $xml = lookup_release($discid) || return;
    
    $xpath->set_xml($xml);

    # get the release; if there is more than one, take the first one
    # TODO: configurable release selection criteria
    my $release_count = $xpath->findvalue('count(//release)');
    my ($release) = $xpath->findnodes('//release[1]');
    $info{RELEASE_MBID} = $xpath->findvalue('@id', $release)->value;
    $info{ALBUM}        = $xpath->findvalue('title', $release)->value;
    $info{ARTIST}       = $xpath->findvalue('artist-credit/name-credit/artist/name', $release)->value;

    # TODO: get release date

    my $ua = LWP::UserAgent->new;
    my $tracknum = 1;
    for my $track_node ($xpath->findnodes('.//track-list/track', $release)) {
        my $prefix = sprintf('TRACK%02d', $tracknum);
        #$info{"$prefix.MB_TRACKID"} = $xpath->findvalue('@id', $track_node);
        my $recording_mbid = $info{"$prefix.RECORDING_MBID"} = $xpath->findvalue('recording/@id', $track_node)->value;
        $info{"$prefix.TITLE"}          = $xpath->findvalue('recording/title', $track_node)->value;
        $info{"$prefix.ARTIST"}         = $xpath->findvalue('recording/artist-credit/name-credit/artist/name', $track_node)->value || $info{ARTIST};
        $info{TRACKS}[$tracknum]{TITLE} = $info{"$prefix.TITLE"};
        $info{TRACKS}[$tracknum]{ARTIST} = $info{"$prefix.ARTIST"};
        #my $uri = URI->new("http://musicbrainz.org/ws/2/recording/$recording_mbid");
        #$uri->query_form(inc => 'artists');
        #my $res = $ua->get($uri);
        #die $res->decoded_content;

        #TODO: get track relations (Covers, etc.)

        $tracknum++;
    }

    return \%info;
}

# module return
1;

=begin MBZ API version 1

sub lookup_release {
    my ($discid) = @_;
    my $ua = LWP::UserAgent->new;

    my $uri = URI->new('http://musicbrainz.org/ws/1/release/');
    $uri->query_form(type => 'xml', discid => $discid);

    my $res = $ua->get($uri);
    return $res->decoded_content;
}

sub get_musicbrainz_info {
    my ($discid) = @_;
    my %info;

    $info{MBZ_DISCID} = $discid;

    my $xpath = XML::XPath->new();

    $xpath->set_xml(lookup_release($discid));

    # TODO: check for more than 1 release?

    $info{MB_RELEASE_ID} = $xpath->findvalue('//release/@id');
    $info{ALBUM}         = $xpath->findvalue('//release/title');
    $info{ARTIST}        = $xpath->findvalue('//release/artist/name');
    $info{TRACKS}        = [];

    # TODO: get release date

    my $tracknum = 1;
    for my $track_node ($xpath->findnodes('//track-list/track')) {
        $info{TRACKS}[$tracknum]{MB_TRACKID} = $xpath->findvalue('@id', $track_node);
        $info{TRACKS}[$tracknum]{TITLE}      = $xpath->findvalue('title', $track_node);
        $info{TRACKS}[$tracknum]{ARTIST}     = $xpath->findvalue('artist/name', $track_node) || $info{ARTIST};
        $tracknum++;
    }

    return %info;
}

=cut

=begin WebService::MusicBrainz code

    my $ws_artists = WebService::MusicBrainz->new_artist;
    my $ws_releases = WebService::MusicBrainz->new_release;
    my $ws_tracks = WebService::MusicBrainz->new_track;

    # search on the discid
    my $response = $ws_releases->search({ DISCID => $discid });

    # save this object, since WS::MBZ deletes it when you fetch it
    # TODO: bug report to WS::MBZ?
    my $release = $response->release;

    # return undef if there is no matching release for this DiscID
    return unless defined $release;

    # search again, using the MBID of the first release found
    # TODO: deal with multiple releases found?
    # include tracks and artist info
    $response = $ws_releases->search({
        MBID => $release->id, 
        INC => 'discs tracks artist release-events counts',
    });

    # get the fully filled out Release object (that represents the disc)
    $release = $response->release;

    if (defined $release->artist) {
        $info{ARTIST} = $release->artist->name;
    }
    if (defined $release->title) {
        $info{ALBUM} = $release->title;
    }

    # this is ID3v2:TDRL = Release Date
    # (for now we just take the first date)
    my $release_date = eval { @{ $release->release_event_list->events }[0]->date };
    $release_date = '' if $@;

    $info{DATE} = $release_date;

    # get full info on each of the tracks
    my @tracks;
    my $track_num = 1;
    for my $track_id (map { $_->id } @{ $release->track_list->tracks }) {
        my $response = $ws_tracks->search({ 
            MBID => $track_id,
            INC => 'artist track-rels',
        });
        my $track = $response->track;
        my $prefix = sprintf('TRACK%02d', $track_num);
        $info{"$prefix.TITLE"} = $track->title;
        #if (defined $track->artist && $track->artist->name ne $release->artist->name) {
            $info{"$prefix.ARTIST"} = $track->artist->name;
            $info{"$prefix.DATE"} = $release_date;
        #}
        push @tracks, $track;


        if (defined $track->relation_list) {
            for my $relation (@{ $track->relation_list->relations }) {
                #warn $relation->type, $relation->target;
                my $response = $ws_tracks->search({
                    MBID => $relation->target,
                    INC => 'artist releases',
                });
                my $track = $response->track;
                $info{"$prefix.ORIGINAL_ARTIST"} = $track->artist->name;
                $info{"$prefix.ORIGINAL_ALBUM"} = 
                    ( (@{ $track->release_list->releases })[0]->title );
            }
        }

        $track_num++;
    }

=cut
