using FrameProcessor.Domain;
using FrameProcessor.ImagePipeline;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

namespace FrameProcessor.Tests;

public class PaletteFactoryTests
{
    private static readonly IReadOnlyList<PaletteEntry> Spectra6 = new[]
    {
        new PaletteEntry("black",  Color.FromPixel(new Rgba32(0x1F, 0x22, 0x26, 0xFF)), Color.FromPixel(new Rgba32(0x00, 0x00, 0x00, 0xFF))),
        new PaletteEntry("white",  Color.FromPixel(new Rgba32(0xB9, 0xC7, 0xC9, 0xFF)), Color.FromPixel(new Rgba32(0xFF, 0xFF, 0xFF, 0xFF))),
        new PaletteEntry("blue",   Color.FromPixel(new Rgba32(0x23, 0x3F, 0x8E, 0xFF)), Color.FromPixel(new Rgba32(0x00, 0x00, 0xFF, 0xFF))),
        new PaletteEntry("green",  Color.FromPixel(new Rgba32(0x35, 0x56, 0x3A, 0xFF)), Color.FromPixel(new Rgba32(0x00, 0xFF, 0x00, 0xFF))),
        new PaletteEntry("red",    Color.FromPixel(new Rgba32(0x62, 0x20, 0x1E, 0xFF)), Color.FromPixel(new Rgba32(0xFF, 0x00, 0x00, 0xFF))),
        new PaletteEntry("yellow", Color.FromPixel(new Rgba32(0xC1, 0xBB, 0x1E, 0xFF)), Color.FromPixel(new Rgba32(0xFF, 0xFF, 0x00, 0xFF))),
    };

    [Fact]
    public void BuildDisplay_PreservesOrderAndCount()
    {
        var palette = PaletteFactory.BuildDisplay(Spectra6).ToArray();

        Assert.Equal(Spectra6.Count, palette.Length);
        for (var i = 0; i < Spectra6.Count; i++)
        {
            Assert.Equal(Spectra6[i].DisplayColor, palette[i]);
        }
    }

    [Fact]
    public void BuildDevice_PreservesOrderAndCount()
    {
        var palette = PaletteFactory.BuildDevice(Spectra6).ToArray();

        Assert.Equal(Spectra6.Count, palette.Length);
        for (var i = 0; i < Spectra6.Count; i++)
        {
            Assert.Equal(Spectra6[i].DeviceColor, palette[i]);
        }
    }

    [Fact]
    public void BuildDisplay_AndBuildDevice_DiffWhenColorsDiffer()
    {
        var display = PaletteFactory.BuildDisplay(Spectra6).ToArray();
        var device = PaletteFactory.BuildDevice(Spectra6).ToArray();

        Assert.NotEqual(display, device);
    }

    [Fact]
    public void Build_OnEmptyList_ReturnsEmptyPalette()
    {
        Assert.Equal(0, PaletteFactory.BuildDisplay(Array.Empty<PaletteEntry>()).Length);
        Assert.Equal(0, PaletteFactory.BuildDevice(Array.Empty<PaletteEntry>()).Length);
    }

    [Fact]
    public void Build_NullEntries_Throws()
    {
        Assert.Throws<ArgumentNullException>(() => PaletteFactory.BuildDisplay(null!));
        Assert.Throws<ArgumentNullException>(() => PaletteFactory.BuildDevice(null!));
    }
}
