namespace NATS.Server.JetStream.Consumers;

/// <summary>
/// Tracks whether there are active subscribers on a consumer's delivery subject.
/// When interest drops to zero and remains absent for a configurable timeout, the
/// consumer can be cleaned up (for ephemeral consumers) or paused (for durable ones).
/// Go reference: consumer.go hasDeliveryInterest, deleteNotActive.
/// </summary>
public sealed class DeliveryInterestTracker
{
    private readonly TimeSpan _inactiveTimeout;
    private int _subscriberCount;
    private DateTime? _lastUnsubscribeUtc;

    public DeliveryInterestTracker(TimeSpan? inactiveTimeout = null)
    {
        _inactiveTimeout = inactiveTimeout ?? TimeSpan.FromSeconds(30);
    }

    /// <summary>True when at least one subscriber exists on the delivery subject.</summary>
    public bool HasInterest => Volatile.Read(ref _subscriberCount) > 0;

    /// <summary>Current subscriber count.</summary>
    public int SubscriberCount => Volatile.Read(ref _subscriberCount);

    /// <summary>
    /// True when interest has been absent for longer than the inactive timeout.
    /// Used by ephemeral consumers to trigger auto-deletion.
    /// Go reference: consumer.go deleteNotActive.
    /// </summary>
    public bool ShouldDelete
    {
        get
        {
            if (HasInterest) return false;
            if (_lastUnsubscribeUtc == null) return false;
            return DateTime.UtcNow - _lastUnsubscribeUtc.Value >= _inactiveTimeout;
        }
    }

    /// <summary>Records a new subscriber on the delivery subject.</summary>
    public void OnSubscribe()
    {
        Interlocked.Increment(ref _subscriberCount);
        _lastUnsubscribeUtc = null; // Reset the inactivity timer
    }

    /// <summary>Records removal of a subscriber from the delivery subject.</summary>
    public void OnUnsubscribe()
    {
        var count = Interlocked.Decrement(ref _subscriberCount);
        if (count <= 0)
        {
            Interlocked.Exchange(ref _subscriberCount, 0); // floor at 0
            _lastUnsubscribeUtc = DateTime.UtcNow;
        }
    }

    /// <summary>Resets the tracker to initial state.</summary>
    public void Reset()
    {
        Interlocked.Exchange(ref _subscriberCount, 0);
        _lastUnsubscribeUtc = null;
    }
}
