using System;
using System.IO;
using NetVips;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using Image = NetVips.Image;
namespace API.Extensions;
public static class ImageExtensions
{
    public static int GetResolution(this Image image)
    {
        return image.Width * image.Height;
    }
    /// 
    /// Smaller is better
    /// 
    /// 
    /// 
    /// 
    public static float GetMeanSquaredError(this Image img1, Image img2)
    {
        if (img1.Width != img2.Width || img1.Height != img2.Height)
        {
            img2.Mutate(x => x.Resize(img1.Width, img1.Height));
        }
        double totalDiff = 0;
        for (var y = 0; y < img1.Height; y++)
        {
            for (var x = 0; x < img1.Width; x++)
            {
                var pixel1 = img1[x, y];
                var pixel2 = img2[x, y];
                var diff = Math.Pow(pixel1.R - pixel2.R, 2) +
                           Math.Pow(pixel1.G - pixel2.G, 2) +
                           Math.Pow(pixel1.B - pixel2.B, 2);
                totalDiff += diff;
            }
        }
        return (float)(totalDiff / (img1.Width * img1.Height));
    }
    public static float GetSimilarity(this string imagePath1, string imagePath2)
    {
        if (!File.Exists(imagePath1) || !File.Exists(imagePath2))
        {
            throw new FileNotFoundException("One or both image files do not exist");
        }
        // Calculate similarity score
        return CalculateSimilarity(imagePath1, imagePath2);
    }
    /// 
    /// Determines which image is "better" based on similarity and resolution.
    /// 
    /// Path to first image
    /// Path to second image
    /// Minimum similarity to consider images similar
    /// The path of the better image
    public static string GetBetterImage(this string imagePath1, string imagePath2, float similarityThreshold = 0.7f)
    {
        if (!File.Exists(imagePath1) || !File.Exists(imagePath2))
        {
            throw new FileNotFoundException("One or both image files do not exist");
        }
        // Calculate similarity score
        var similarity = CalculateSimilarity(imagePath1, imagePath2);
        using var img1 = Image.NewFromFile(imagePath1, access: Enums.Access.Sequential);
        using var img2 = Image.NewFromFile(imagePath2, access: Enums.Access.Sequential);
        var resolution1 = img1.Width * img1.Height;
        var resolution2 = img2.Width * img2.Height;
        // If images are similar, choose the one with higher resolution
        if (similarity >= similarityThreshold)
        {
            return resolution1 >= resolution2 ? imagePath1 : imagePath2;
        }
        // If images are not similar, allow the new image
        return imagePath2;
    }
    /// 
    /// Calculate a similarity score (0-1f) based on resolution difference and MSE.
    /// 
    /// 
    /// 
    /// 
    private static float CalculateSimilarity(string imagePath1, string imagePath2)
    {
        if (!File.Exists(imagePath1) || !File.Exists(imagePath2))
        {
            return -1;
        }
        using var img1 = Image.NewFromFile(imagePath1, access: Enums.Access.Sequential);
        using var img2 = Image.NewFromFile(imagePath2, access: Enums.Access.Sequential);
        var res1 = img1.Width * img1.Height;
        var res2 = img2.Width * img2.Height;
        var resolutionDiff = Math.Abs(res1 - res2) / (float)Math.Max(res1, res2);
        using var imgSharp1 = SixLabors.ImageSharp.Image.Load(imagePath1);
        using var imgSharp2 = SixLabors.ImageSharp.Image.Load(imagePath2);
        var mse = imgSharp1.GetMeanSquaredError(imgSharp2);
        var normalizedMse = 1f - Math.Min(1f, mse / 65025f); // Normalize based on max color diff
        // Final similarity score (weighted)
        return Math.Max(0f, 1f - (resolutionDiff * 0.5f) - (1f - normalizedMse) * 0.5f);
    }
}