using Scry.Core.Imaging;
using SkiaSharp;
using Xunit;

namespace Scry.Tests;

public class ImagePreprocessorTests
{
    [Fact]
    public void Resize_ProducesCorrectDimensions()
    {
        using var bitmap = CreateTestBitmap(100, 100);
        
        using var resized = ImagePreprocessor.Resize(bitmap, 32, 32);
        
        Assert.Equal(32, resized.Width);
        Assert.Equal(32, resized.Height);
    }
    
    [Fact]
    public void ToGrayscale_ProducesGrayscaleImage()
    {
        using var bitmap = CreateColorBitmap(10, 10);
        
        using var grayscale = ImagePreprocessor.ToGrayscale(bitmap);
        
        Assert.Equal(10, grayscale.Width);
        Assert.Equal(10, grayscale.Height);
    }
    
    [Fact]
    public void ApplyClahe_PreservesDimensions()
    {
        using var bitmap = CreateTestBitmap(64, 64);
        
        using var result = ImagePreprocessor.ApplyClahe(bitmap);
        
        Assert.Equal(64, result.Width);
        Assert.Equal(64, result.Height);
    }
    
    [Fact]
    public void ApplyClahe_EnhancesContrast()
    {
        using var bitmap = CreateLowContrastBitmap(64, 64);
        
        using var result = ImagePreprocessor.ApplyClahe(bitmap);
        
        Assert.NotNull(result);
        Assert.Equal(bitmap.Width, result.Width);
        Assert.Equal(bitmap.Height, result.Height);
    }
    
    [Theory]
    [InlineData("varying_quality/test1.jpg")]
    [InlineData("low_light/glare_toploader.png")]
    [InlineData("foil/rainbow_foil_secret_lair.jpg")]
    public void ApplyClahe_RealImages_DoesNotCrash(string imagePath)
    {
        var fullPath = Path.Combine("TestImages", imagePath);
        if (!File.Exists(fullPath))
        {
            return;
        }
        
        using var bitmap = SKBitmap.Decode(fullPath);
        Assert.NotNull(bitmap);
        
        using var result = ImagePreprocessor.ApplyClahe(bitmap);
        
        Assert.Equal(bitmap.Width, result.Width);
        Assert.Equal(bitmap.Height, result.Height);
    }
    
    private static SKBitmap CreateTestBitmap(int width, int height)
    {
        var bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul);
        using var canvas = new SKCanvas(bitmap);
        canvas.Clear(SKColors.Gray);
        return bitmap;
    }
    
    private static SKBitmap CreateColorBitmap(int width, int height)
    {
        var bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul);
        for (var y = 0; y < height; y++)
        {
            for (var x = 0; x < width; x++)
            {
                var r = (byte)(x * 255 / width);
                var g = (byte)(y * 255 / height);
                var b = (byte)((x + y) * 127 / (width + height));
                bitmap.SetPixel(x, y, new SKColor(r, g, b));
            }
        }
        return bitmap;
    }
    
    private static SKBitmap CreateLowContrastBitmap(int width, int height)
    {
        var bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul);
        for (var y = 0; y < height; y++)
        {
            for (var x = 0; x < width; x++)
            {
                var gray = (byte)(120 + (x + y) % 20);
                bitmap.SetPixel(x, y, new SKColor(gray, gray, gray));
            }
        }
        return bitmap;
    }
    
    private static (byte Min, byte Max) GetLuminanceRange(SKBitmap bitmap)
    {
        byte min = 255;
        byte max = 0;
        
        for (var y = 0; y < bitmap.Height; y++)
        {
            for (var x = 0; x < bitmap.Width; x++)
            {
                var pixel = bitmap.GetPixel(x, y);
                var luminance = (byte)(0.299 * pixel.Red + 0.587 * pixel.Green + 0.114 * pixel.Blue);
                min = Math.Min(min, luminance);
                max = Math.Max(max, luminance);
            }
        }
        
        return (min, max);
    }
}
