using System;
using System.Threading;
using MusicMetaTagger.Client.AllMusicGuide.Services.Searchers;
using MusicMetaTagger.Core.Model;
using MusicMetaTagger.Core.Queries;
using MusicMetaTagger.Core.Services;

namespace MusicMetaTagger.Client.AllMusicGuide.Services
{
	public class TrackSearcher : ITrackSearcher
	{
		private readonly IMusicGuide _musicGuide;
		private readonly ITrackSearcher[] _searchers;

		public TrackSearcher(IMusicGuide musicGuide)
		{
			_musicGuide = musicGuide;
			_searchers = new ITrackSearcher[]
			             	{
			             		new AlbumArtistSearcher(_musicGuide), 
			             		new SongArtistSearcher(_musicGuide),
			             		new AlbumSearcher(_musicGuide), 
			             	};

			foreach (var searcher in _searchers)
				searcher.SearchStatusUpdate += NestedSearcher_SearchStatusUpdate;
		}

		public event StatusHandler SearchStatusUpdate;

		private void OnStatusUpdate(string status)
		{
			if (SearchStatusUpdate != null)
				SearchStatusUpdate.Invoke(new StatusEventArgs(status));
		}

		void NestedSearcher_SearchStatusUpdate(StatusEventArgs data)
		{
			if (SearchStatusUpdate != null)
				SearchStatusUpdate.Invoke(data);
		}

		public Track SearchTrack(TrackQuery trackQuery, CancellationToken canellationToken)
		{
			var statusSearch =
				String.Format("Searching for Album - Artist - Track: '{0} - {1} - {2}'", 
					trackQuery.AlbumTitle ?? "unknown", trackQuery.ArtistName ?? "unknown", 
					trackQuery.TrackTitle);
			OnStatusUpdate(statusSearch);

			Track matchingTrack = null;
			foreach (var searcher in _searchers)
			{
				var track = searcher.SearchTrack(trackQuery, canellationToken);
				if (track != null)
				{
					matchingTrack = track;
					break;
				}
				if (canellationToken.IsCancellationRequested)
					return null;
			}

			if (matchingTrack != null)
			{
				TrackMatchFound(matchingTrack);
				return matchingTrack;
			}

			OnStatusUpdate("No Matches Found");
			return null;
		}

		/// <summary>
		///   Updates the callback with the matching track
		/// </summary>
		private void TrackMatchFound(Track matchTrack)
		{
			var artistName = !string.IsNullOrEmpty(matchTrack.PerformerIds[0])
								? _musicGuide.GetArtist(matchTrack.PerformerIds[0]).ArtistName
								: "Unknown";
			var matchAlbumInfo = _musicGuide.GetAlbum(matchTrack.AlbumId);
			var status = String.Format("Found Match: {0} - {1} - {2} - {3}", artistName, matchAlbumInfo.Title, matchTrack.TrackTitle, matchTrack.TrackLength);
			OnStatusUpdate(status);
		}
	}
}