using NATS.Server.JetStream.Consumers;

namespace NATS.Server.JetStream.Tests.JetStream.Consumers;

/// <summary>
/// Tests for priority group pin ID management.
/// Go reference: consumer.go (setPinnedTimer, assignNewPinId).
/// </summary>
public class PriorityGroupPinningTests
{
    [Fact]
    public void AssignPinId_generates_unique_ids()
    {
        var mgr = new PriorityGroupManager();
        mgr.Register("group-1", "consumer-a", priority: 0);

        var pin1 = mgr.AssignPinId("group-1", "consumer-a");
        var pin2 = mgr.AssignPinId("group-1", "consumer-a");

        pin1.ShouldNotBeNullOrEmpty();
        pin2.ShouldNotBeNullOrEmpty();
        pin1.ShouldNotBe(pin2); // each assignment is unique
    }

    [Fact]
    public void ValidatePinId_accepts_current()
    {
        var mgr = new PriorityGroupManager();
        mgr.Register("group-1", "consumer-a", priority: 0);

        var pin = mgr.AssignPinId("group-1", "consumer-a");
        mgr.ValidatePinId("group-1", pin).ShouldBeTrue();
    }

    [Fact]
    public void ValidatePinId_rejects_expired()
    {
        var mgr = new PriorityGroupManager();
        mgr.Register("group-1", "consumer-a", priority: 0);

        var pin1 = mgr.AssignPinId("group-1", "consumer-a");
        var pin2 = mgr.AssignPinId("group-1", "consumer-a"); // replaces pin1

        mgr.ValidatePinId("group-1", pin1).ShouldBeFalse();
        mgr.ValidatePinId("group-1", pin2).ShouldBeTrue();
    }

    [Fact]
    public void UnassignPinId_clears()
    {
        var mgr = new PriorityGroupManager();
        mgr.Register("group-1", "consumer-a", priority: 0);

        var pin = mgr.AssignPinId("group-1", "consumer-a");
        mgr.UnassignPinId("group-1");

        mgr.ValidatePinId("group-1", pin).ShouldBeFalse();
    }

    [Fact]
    public void ValidatePinId_returns_false_for_unknown_group()
    {
        var mgr = new PriorityGroupManager();
        mgr.ValidatePinId("unknown", "any-pin").ShouldBeFalse();
    }

    [Fact]
    public void UnassignPinId_noop_for_unknown_group()
    {
        var mgr = new PriorityGroupManager();
        // Should not throw
        Should.NotThrow(() => mgr.UnassignPinId("unknown"));
    }

    [Fact]
    public void PinId_is_22_chars()
    {
        var mgr = new PriorityGroupManager();
        mgr.Register("g1", "c1", priority: 0);

        var pin = mgr.AssignPinId("g1", "c1");
        pin.Length.ShouldBe(22);
    }
}
