using NATS.Server.JetStream;

namespace NATS.Server.JetStream.Tests.JetStream;

/// <summary>
/// Tests for InterestRetentionPolicy per-consumer ack tracking.
/// Go reference: stream.go checkInterestState/noInterest.
/// </summary>
public class InterestRetentionTests
{
    [Fact]
    public void ShouldRetain_true_when_consumers_have_not_acked()
    {
        var policy = new InterestRetentionPolicy();
        policy.RegisterInterest("consumer-A", "orders.>");
        policy.RegisterInterest("consumer-B", "orders.>");

        policy.ShouldRetain(1, "orders.new").ShouldBeTrue();
    }

    [Fact]
    public void ShouldRetain_false_when_all_consumers_acked()
    {
        var policy = new InterestRetentionPolicy();
        policy.RegisterInterest("consumer-A", "orders.>");
        policy.RegisterInterest("consumer-B", "orders.>");

        policy.AcknowledgeDelivery("consumer-A", 1);
        policy.ShouldRetain(1, "orders.new").ShouldBeTrue(); // B hasn't acked

        policy.AcknowledgeDelivery("consumer-B", 1);
        policy.ShouldRetain(1, "orders.new").ShouldBeFalse(); // both acked
    }

    [Fact]
    public void ShouldRetain_ignores_consumers_without_interest()
    {
        var policy = new InterestRetentionPolicy();
        policy.RegisterInterest("consumer-A", "orders.>");
        policy.RegisterInterest("consumer-B", "billing.>"); // no interest in orders

        policy.AcknowledgeDelivery("consumer-A", 1);
        policy.ShouldRetain(1, "orders.new").ShouldBeFalse(); // B has no interest
    }

    [Fact]
    public void UnregisterInterest_removes_consumer()
    {
        var policy = new InterestRetentionPolicy();
        policy.RegisterInterest("consumer-A", "x.>");
        policy.RegisterInterest("consumer-B", "x.>");

        policy.UnregisterInterest("consumer-B");

        // Only A needs to ack
        policy.AcknowledgeDelivery("consumer-A", 1);
        policy.ShouldRetain(1, "x.y").ShouldBeFalse();
    }

    [Fact]
    public void ShouldRetain_false_when_no_consumers_registered()
    {
        var policy = new InterestRetentionPolicy();
        policy.ShouldRetain(1, "any.subject").ShouldBeFalse();
    }

    [Fact]
    public void Multiple_sequences_tracked_independently()
    {
        var policy = new InterestRetentionPolicy();
        policy.RegisterInterest("c1", "x.>");

        policy.AcknowledgeDelivery("c1", 1);
        policy.ShouldRetain(1, "x.y").ShouldBeFalse();
        policy.ShouldRetain(2, "x.y").ShouldBeTrue(); // seq 2 not acked
    }

    [Fact]
    public void ConsumerCount_tracks_registrations()
    {
        var policy = new InterestRetentionPolicy();
        policy.ConsumerCount.ShouldBe(0);

        policy.RegisterInterest("c1", "x.>");
        policy.RegisterInterest("c2", "y.>");
        policy.ConsumerCount.ShouldBe(2);

        policy.UnregisterInterest("c1");
        policy.ConsumerCount.ShouldBe(1);
    }
}
