// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see .
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Blurhash.SkiaSharp;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Microsoft.Extensions.Logging;
using SkiaSharp;
#nullable enable
namespace Kyoo.Core.Controllers
{
	/// 
	/// Download images and retrieve the path of those images for a resource.
	/// 
	public class ThumbnailsManager : IThumbnailsManager
	{
		/// 
		/// A logger to report errors.
		/// 
		private readonly ILogger _logger;
		private readonly IHttpClientFactory _clientFactory;
		/// 
		/// Create a new .
		/// 
		/// Client factory
		/// A logger to report errors
		public ThumbnailsManager(IHttpClientFactory clientFactory,
			ILogger logger)
		{
			_clientFactory = clientFactory;
			_logger = logger;
		}
		private static async Task _WriteTo(SKBitmap bitmap, string path, int quality)
		{
			SKData data = bitmap.Encode(SKEncodedImageFormat.Webp, quality);
			await using Stream reader = data.AsStream();
			await using Stream file = File.Create(path);
			await reader.CopyToAsync(file);
		}
		private async Task _DownloadImage(Image? image, string localPath, string what)
		{
			if (image == null)
				return;
			try
			{
				_logger.LogInformation("Downloading image {What}", what);
				HttpClient client = _clientFactory.CreateClient();
				HttpResponseMessage response = await client.GetAsync(image.Source);
				response.EnsureSuccessStatusCode();
				await using Stream reader = await response.Content.ReadAsStreamAsync();
				using SKCodec codec = SKCodec.Create(reader);
				SKImageInfo info = codec.Info;
				info.ColorType = SKColorType.Rgba8888;
				using SKBitmap original = SKBitmap.Decode(codec, info);
				using SKBitmap high = original.Resize(new SKSizeI(original.Width, original.Height), SKFilterQuality.High);
				await _WriteTo(original, $"{localPath}.{ImageQuality.High.ToString().ToLowerInvariant()}.webp", 80);
				using SKBitmap medium = high.Resize(new SKSizeI((int)(high.Width / 1.5), (int)(high.Height / 1.5)), SKFilterQuality.Medium);
				await _WriteTo(medium, $"{localPath}.{ImageQuality.Medium.ToString().ToLowerInvariant()}.webp", 55);
				using SKBitmap low = medium.Resize(new SKSizeI(original.Width / 2, original.Height / 2), SKFilterQuality.Low);
				await _WriteTo(low, $"{localPath}.{ImageQuality.Low.ToString().ToLowerInvariant()}.webp", 25);
				image.Blurhash = Blurhasher.Encode(low, 4, 3);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "{What} could not be downloaded", what);
			}
		}
		/// 
		public async Task DownloadImages(T item)
			where T : IThumbnails
		{
			if (item == null)
				throw new ArgumentNullException(nameof(item));
			string name = item is IResource res ? res.Slug : "???";
			await _DownloadImage(item.Poster, _GetBaseImagePath(item, "poster"), $"The poster of {name}");
			await _DownloadImage(item.Thumbnail, _GetBaseImagePath(item, "thumbnail"), $"The poster of {name}");
			await _DownloadImage(item.Logo, _GetBaseImagePath(item, "logo"), $"The poster of {name}");
		}
		private static string _GetBaseImagePath(T item, string image)
		{
			string directory = item switch
			{
				IResource res => Path.Combine("./metadata", item.GetType().Name.ToLowerInvariant(), res.Slug),
				_ => Path.Combine("./metadata", typeof(T).Name.ToLowerInvariant())
			};
			Directory.CreateDirectory(directory);
			return Path.Combine(directory, image);
		}
		/// 
		public string GetImagePath(T item, string image, ImageQuality quality)
			where T : IThumbnails
		{
			return $"{_GetBaseImagePath(item, image)}.{quality.ToString().ToLowerInvariant()}.webp";
		}
	}
}