using System.Threading.Channels;

namespace ZB.MOM.NatsNet.Server;

internal sealed partial class NatsConsumer
{
    private readonly HashSet<string> _internalSubscriptions = new(StringComparer.Ordinal);
    private readonly Channel<bool> _updateChannel = Channel.CreateBounded<bool>(4);
    private Channel<bool>? _monitorQuitChannel = Channel.CreateBounded<bool>(1);

    internal ChannelReader<bool>? MonitorQuitC()
    {
        _mu.EnterReadLock();
        try
        {
            return _monitorQuitChannel?.Reader;
        }
        finally
        {
            _mu.ExitReadLock();
        }
    }

    internal void SignalMonitorQuit()
    {
        _mu.EnterWriteLock();
        try
        {
            var channel = _monitorQuitChannel;
            if (channel is null)
                return;

            channel.Writer.TryWrite(true);
            channel.Writer.TryComplete();
            _monitorQuitChannel = null;
        }
        finally
        {
            _mu.ExitWriteLock();
        }
    }

    internal ChannelReader<bool> UpdateC() => _updateChannel.Reader;

    internal bool CheckQueueInterest(string? queue = null)
    {
        _mu.EnterReadLock();
        try
        {
            if (_closed)
                return false;

            if (_internalSubscriptions.Count > 0)
                return true;

            return !string.IsNullOrWhiteSpace(queue) && _internalSubscriptions.Contains(queue);
        }
        finally
        {
            _mu.ExitReadLock();
        }
    }

    internal void ClearNode() => ClearRaftNode();

    internal bool IsLeaderInternal() => IsLeader();

    internal ConsumerInfo? HandleClusterConsumerInfoRequest() =>
        IsLeader() && !_closed ? GetInfo() : null;

    internal bool SubscribeInternal(string subject)
    {
        if (string.IsNullOrWhiteSpace(subject))
            return false;

        _mu.EnterWriteLock();
        try
        {
            var added = _internalSubscriptions.Add(subject);
            if (added)
                _updateChannel.Writer.TryWrite(true);
            return added;
        }
        finally
        {
            _mu.ExitWriteLock();
        }
    }

    internal bool Unsubscribe(string subject)
    {
        if (string.IsNullOrWhiteSpace(subject))
            return false;

        _mu.EnterWriteLock();
        try
        {
            var removed = _internalSubscriptions.Remove(subject);
            if (removed)
                _updateChannel.Writer.TryWrite(true);
            return removed;
        }
        finally
        {
            _mu.ExitWriteLock();
        }
    }

    internal DateTime CreatedTime()
    {
        _mu.EnterReadLock();
        try
        {
            return Created;
        }
        finally
        {
            _mu.ExitReadLock();
        }
    }

    internal void SetCreatedTime(DateTime created)
    {
        _mu.EnterWriteLock();
        try
        {
            Created = created;
        }
        finally
        {
            _mu.ExitWriteLock();
        }
    }

    internal bool HasDeliveryInterest()
    {
        return HasDeliveryInterest(_hasLocalDeliveryInterest);
    }
}
