using System.Threading.Channels;

namespace NATS.Server.Raft;

/// <summary>
/// Channel-based queue for committed log entries awaiting state machine application.
/// Go reference: raft.go:150-160 (applied/processed fields), raft.go:2100-2150 (ApplyQ).
/// </summary>
public sealed class CommitQueue<T>
{
    private readonly Channel<T> _channel = Channel.CreateUnbounded<T>(
        new UnboundedChannelOptions { SingleReader = false, SingleWriter = false });

    /// <summary>
    /// Approximate number of items waiting to be dequeued.
    /// </summary>
    public int Count => _channel.Reader.Count;

    /// <summary>
    /// Enqueues an item for state machine application.
    /// </summary>
    public ValueTask EnqueueAsync(T item, CancellationToken ct = default)
        => _channel.Writer.WriteAsync(item, ct);

    /// <summary>
    /// Dequeues the next committed entry, waiting if none are available.
    /// </summary>
    public ValueTask<T> DequeueAsync(CancellationToken ct = default)
        => _channel.Reader.ReadAsync(ct);

    /// <summary>
    /// Attempts a non-blocking dequeue. Returns true if an item was available.
    /// </summary>
    public bool TryDequeue(out T? item)
        => _channel.Reader.TryRead(out item);

    /// <summary>
    /// Marks the channel as complete so no more items can be enqueued.
    /// Readers will drain remaining items and then receive completion.
    /// </summary>
    public void Complete()
        => _channel.Writer.Complete();
}
