using ErsatzTV.Core.Images;
using NUnit.Framework;
using Shouldly;

namespace ErsatzTV.Core.Tests.Images;

[TestFixture]
public class RemoteImageDecodeBudgetTests
{
    private static readonly Uri Uri = new("https://example.com/logo.png");

    // the product is the real bound: 2500x2500 x600 is affordable on each axis alone but not together
    [Test]
    public void Should_Reject_Dimensions_And_Frames_Affordable_Alone_But_Not_Together()
    {
        ((long)2500 * 2500).ShouldBeLessThanOrEqualTo(RemoteImageDecodeBudget.MaxRemoteDecodedPixels);
        600.ShouldBeLessThanOrEqualTo(RemoteImageDecodeBudget.MaxRemoteFrames);

        InvalidOperationException ex = Should.Throw<InvalidOperationException>(
            () => RemoteImageDecodeBudget.EnsureDecodeAffordable(2500, 2500, 600, Uri));
        ex.Message.ShouldContain("pixel limit");
    }

    [Test]
    public void Should_Reject_Too_Many_Frames_Even_When_Each_Is_Tiny() =>
        Should.Throw<InvalidOperationException>(
                () => RemoteImageDecodeBudget.EnsureDecodeAffordable(8, 8, RemoteImageDecodeBudget.MaxRemoteFrames + 1, Uri))
            .Message.ShouldContain("frame limit");

    [Test]
    public void Should_Reject_A_Single_Oversized_Frame() =>
        Should.Throw<InvalidOperationException>(
                () => RemoteImageDecodeBudget.EnsureDimensionsAffordable(30000, 30000, Uri))
            .Message.ShouldContain("pixel limit");

    [Test]
    public void Should_Allow_A_Single_Large_Still_Within_Budget() =>
        Should.NotThrow(() => RemoteImageDecodeBudget.EnsureDecodeAffordable(7680, 4320, 1, Uri));

    [Test]
    public void Should_Charge_At_Least_One_Frame_When_Header_Reports_None() =>
        Should.Throw<InvalidOperationException>(
            () => RemoteImageDecodeBudget.EnsureDecodeAffordable(30000, 30000, 0, Uri));

    [Test]
    public void Should_Afford_Fewer_Frames_As_Frames_Get_Larger()
    {
        RemoteImageDecodeBudget.AffordableFrames(8, 8).ShouldBe(RemoteImageDecodeBudget.MaxRemoteFrames);
        RemoteImageDecodeBudget.AffordableFrames(1000, 1000).ShouldBe(50);
        RemoteImageDecodeBudget.AffordableFrames(7000, 7000).ShouldBe(1);
    }
}
