using Exsersewo.Common.Utilities;
using ImageMagick;
using Kynareth.Models;

namespace Kynareth.Managers;

public static partial class ImageManager
{
	private static List<ImageGenerationEndpoint> GenerationEndpoints;

	private static string GenerationTemplateBaseFolder;
	
	static void ConfigureGeneration(IConfiguration configuration, IWebHostEnvironment _appEnvironment)
	{
		GenerationTemplateBaseFolder = Path.Combine(_appEnvironment.WebRootPath, configuration.GetValue<string>("ShitpostBot:Folder"));
		GenerationEndpoints = configuration.GetSection("ShitpostBot:Templates").Get<List<ImageGenerationEndpoint>>();
	}
	
	public static async Task<object> GenerateImageAsync(string template, string variant, string[] sources)
	{
		ImageGenerationImage imageTemplate = null;

		var endpoint = GenerationEndpoints.FirstOrDefault(e => e.Name.ToLowerInvariant().Equals(template.ToLowerInvariant()));
				
		if (endpoint is null)
		{
			var ex = new ArgumentException($"Couldn't find endpoint named \"{template}\"", nameof(template));

			return GetResult(StatusCodes.Status404NotFound, EventResult.FromFailureException(ex.Message, ex));
		}

		if (endpoint.SourcesRequired > sources.Length)
		{
			var ex = new ArgumentException("Not enough sources provided", nameof(sources));

			return GetResult(StatusCodes.Status400BadRequest, EventResult.FromFailureException(ex.Message, ex));
		}

		if (!string.IsNullOrWhiteSpace(variant))
		{
			imageTemplate = endpoint.Variants?
				.FirstOrDefault(v => v.Name.ToLowerInvariant().Equals(variant.ToLowerInvariant()));

			if (imageTemplate is null)
			{
				var ex = new ArgumentException(
					$"Invalid variant given \"{variant}\" for endpoint \"{template}\"",
					nameof(variant)
				);

				return GetResult(StatusCodes.Status400BadRequest, EventResult.FromFailureException(ex.Message, ex));
			}
		}
		else
		{
			imageTemplate = endpoint;
		}

		string image = Path.Combine(GenerationTemplateBaseFolder, !string.IsNullOrWhiteSpace(endpoint.Folder) ? endpoint.Folder : "", imageTemplate.Image);
			
		using MagickImage templateImage = new(System.IO.File.ReadAllBytes(image));
		using MagickImage baseImage = new(MagickColors.Transparent, templateImage.Width, templateImage.Height);

		baseImage.Format = MagickFormat.Png;

		if (imageTemplate.PlaceUnder)
		{
			await AddSourcesToImage(baseImage, imageTemplate, sources);
		}
			
		baseImage.Composite(templateImage, Gravity.Northwest, CompositeOperator.Over);

		if (!imageTemplate.PlaceUnder)
		{
			await AddSourcesToImage(baseImage, imageTemplate, sources);
		}

		return baseImage.ToByteArray();
	}

	static async Task AddSourcesToImage(MagickImage image, ImageGenerationImage template, IEnumerable<string> sources)
	{
		int img = 0;
		foreach (var src in sources)
		{
			var position = template.Positions.ElementAtOrDefault(img);

			using MagickImage srcImg = new MagickImage(await HttpWebClient.GetStreamAsync(new Uri(src)));

			srcImg.Resize(position.Width, position.Height);

			if (position.Rotation != 0)
			{
				srcImg.Rotate(template.Rotate > 0 ? -position.Rotation : position.Rotation);
			}

			string background = !string.IsNullOrWhiteSpace(position.Background) ? $"#{position.Background}" : MagickColors.Transparent.ToHexString();

			var tmp = new MagickImage($"xc:{background}", position.Width, position.Height);

			tmp.Composite(srcImg, Gravity.Center, 0, 0, CompositeOperator.Over);

			image.Composite(tmp, Gravity.Northwest, position.X, position.Y, CompositeOperator.Over);
				
			img++;
		}
	}

	public static IEnumerable<ImageGenerationEndpointRead> GetGenerationEndpoints()
	{
		return GenerationEndpoints.Select(e => new ImageGenerationEndpointRead
		{
			Name = e.Name,
			SourcesRequired = e.SourcesRequired
		});
	}
}