using ApplicationServices;
using DataLayer;
using Dinah.Core.ErrorHandling;
using Dinah.Core.Net.Http;
using LibationFileManager;
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;

namespace FileLiberator;

public class DownloadPdf : Processable, IProcessable<DownloadPdf>
{
	public override string Name => "Download Pdf";
	public override bool Validate(LibraryBook libraryBook)
		=> !string.IsNullOrWhiteSpace(getdownloadUrl(libraryBook))
		&& !libraryBook.Book.PdfExists;

	public override async Task<StatusHandler> ProcessAsync(LibraryBook libraryBook)
	{
		OnBegin(libraryBook);

		try
		{
			var proposedDownloadFilePath = getProposedDownloadFilePath(libraryBook);
			var actualDownloadedFilePath = await downloadPdfAsync(libraryBook, proposedDownloadFilePath);
			var result = verifyDownload(actualDownloadedFilePath);

			if (result.IsSuccess)
			{
				SetFileTime(libraryBook, actualDownloadedFilePath);
				if (Path.GetDirectoryName(actualDownloadedFilePath) is string outputDir)
					SetDirectoryTime(libraryBook, outputDir);
			}
			await libraryBook.UpdatePdfStatusAsync(result.IsSuccess ? LiberatedStatus.Liberated : LiberatedStatus.NotLiberated);

			return result;
		}
		catch (Exception ex)
		{
			Serilog.Log.Logger.Error(ex, "Error downloading PDF");

			var result = new StatusHandler();
			result.AddError($"Error downloading PDF. See log for details. Error summary: {ex.Message}");

			return result;
		}
		finally
		{
			OnCompleted(libraryBook);
		}
	}

	private static string getProposedDownloadFilePath(LibraryBook libraryBook)
	{
		var extension = Path.GetExtension(getdownloadUrl(libraryBook)) ?? ".pdf";

		// if audio file exists, get it's dir. else return base Book dir
		var existingPath = Path.GetDirectoryName(AudibleFileStorage.Audio.GetPath(libraryBook.Book.AudibleProductId));
		if (existingPath is not null)
			return AudibleFileStorage.Audio.GetCustomDirFilename(libraryBook, existingPath, extension);

		return AudibleFileStorage.Audio.GetBooksDirectoryFilename(libraryBook, extension);
	}

	private static string? getdownloadUrl(LibraryBook libraryBook)
		=> libraryBook?.Book?.Supplements?.FirstOrDefault()?.Url;

	private async Task<string> downloadPdfAsync(LibraryBook libraryBook, string proposedDownloadFilePath)
	{
		var api = await libraryBook.GetApiAsync();
		var downloadUrl = await api.GetPdfDownloadLinkAsync(libraryBook.Book.AudibleProductId);

		var progress = new Progress<DownloadProgress>(OnStreamingProgressChanged);

		var client = new HttpClient();

		var actualDownloadedFilePath = await client.DownloadFileAsync(downloadUrl, proposedDownloadFilePath, progress);
		OnFileCreated(libraryBook, actualDownloadedFilePath);

		OnStatusUpdate(actualDownloadedFilePath);
		return actualDownloadedFilePath;
	}

	private static StatusHandler verifyDownload(string actualDownloadedFilePath)
		=> !File.Exists(actualDownloadedFilePath)
		? new StatusHandler { "Downloaded PDF cannot be found" }
		: new StatusHandler();

	public static DownloadPdf Create(Configuration config) => new() { Configuration = config };
	private DownloadPdf() { }
}
