using RioJoy.Core.Overlay;
using Xunit;

namespace RioJoy.Core.Tests.Overlay;

public class FontFitterTests
{
    // Brute-force oracle: the largest integer size whose text fits, mirroring the
    // routine's truncate-to-integer behavior and MinFontSize floor.
    private static double BruteForceBestFit(
        string text, ITextMeasurer m, double width, double height, double cap = 1000)
    {
        double best = FontFitter.MinFontSize;
        for (double s = FontFitter.MinFontSize; s <= cap; s++)
        {
            TextExtent e = m.Measure(text, "f", s);
            if (e.Width <= width && e.Height <= height)
                best = s;
        }
        return best;
    }

    [Theory]
    [InlineData("FIRE", 100, 20)]
    [InlineData("GEAR UP", 120, 24)]
    [InlineData("X", 50, 50)]
    [InlineData("LONGER LABEL TEXT", 80, 16)]
    [InlineData("WW", 10, 40)]   // width-bound, tiny cell
    public void BestFitSize_MatchesBruteForceOracle(string text, double w, double h)
    {
        var m = new LinearTextMeasurer();

        double fit = FontFitter.BestFitSize(text, "f", w, h, m);
        double oracle = BruteForceBestFit(text, m, w, h);

        Assert.Equal(oracle, fit);
    }

    [Fact]
    public void BestFitSize_ResultActuallyFits()
    {
        var m = new LinearTextMeasurer();
        double size = FontFitter.BestFitSize("THROTTLE", "f", 90, 18, m);

        TextExtent e = m.Measure("THROTTLE", "f", size);
        Assert.True(e.Width <= 90 && e.Height <= 18, $"size {size} -> {e.Width}x{e.Height} should fit 90x18");
    }

    [Fact]
    public void BestFitSize_NeverBelowMinimum()
    {
        var m = new LinearTextMeasurer();
        // A cell far too small for any text still yields the floor, not 0/negative.
        double size = FontFitter.BestFitSize("IMPOSSIBLE", "f", 1, 1, m);
        Assert.Equal(FontFitter.MinFontSize, size);
    }

    [Fact]
    public void BestFitSize_EmptyText_Terminates()
    {
        // Empty text has zero width; the loop must still converge (via repeated
        // extents) rather than grow forever.
        double size = FontFitter.BestFitSize("", "f", 100, 100, new LinearTextMeasurer());
        Assert.True(size >= FontFitter.MinFontSize);
    }

    [Fact]
    public void BestFitSize_LargerCell_AllowsLargerFont()
    {
        var m = new LinearTextMeasurer();
        double small = FontFitter.BestFitSize("ABC", "f", 60, 12, m);
        double big = FontFitter.BestFitSize("ABC", "f", 600, 120, m);
        Assert.True(big > small);
    }
}
