namespace ZB.MOM.NatsNet.Server;

internal sealed partial class NatsConsumer
{
    internal static (ulong StreamSequence, ulong DeliverySequence, ulong DeliveryCount, long Timestamp, ulong Pending) ReplyInfo(string subject)
    {
        if (string.IsNullOrWhiteSpace(subject))
            return (0, 0, 0, 0, 0);

        var tokens = subject.Split('.', StringSplitOptions.RemoveEmptyEntries);
        if (tokens.Length < 9 || !string.Equals(tokens[0], "$JS", StringComparison.Ordinal) || !string.Equals(tokens[1], "ACK", StringComparison.Ordinal))
            return (0, 0, 0, 0, 0);

        var deliveryCount = (ulong)Math.Max(0, ParseAckReplyNum(tokens[4]));
        var streamSequence = (ulong)Math.Max(0, ParseAckReplyNum(tokens[5]));
        var deliverySequence = (ulong)Math.Max(0, ParseAckReplyNum(tokens[6]));
        var timestamp = ParseAckReplyNum(tokens[7]);
        var pending = (ulong)Math.Max(0, ParseAckReplyNum(tokens[8]));

        return (streamSequence, deliverySequence, deliveryCount, timestamp, pending);
    }

    internal ulong NextSeq()
    {
        _mu.EnterReadLock();
        try
        {
            return _state.Delivered.Consumer + 1;
        }
        finally
        {
            _mu.ExitReadLock();
        }
    }

    internal bool HasSkipListPending() => false;

    internal void SelectStartingSeqNo()
    {
        _mu.EnterWriteLock();
        try
        {
            var start = Config.OptStartSeq > 0 ? Config.OptStartSeq : 1UL;
            _state.Delivered = new SequencePair { Consumer = 1, Stream = start };
            _state.AckFloor = new SequencePair { Consumer = 0, Stream = start > 0 ? start - 1 : 0 };
            _npc = 0;
            _npf = _state.AckFloor.Stream;
        }
        finally
        {
            _mu.ExitWriteLock();
        }
    }

    internal static bool IsDurableConsumer(ConsumerConfig? config) =>
        config is not null && !string.IsNullOrWhiteSpace(config.Durable);

    internal bool IsDurable() => !string.IsNullOrWhiteSpace(Config.Durable);

    internal string String() => Name;

    internal static string CreateConsumerName() => Guid.NewGuid().ToString("N")[..12];

    internal NatsStream? GetStream()
    {
        _mu.EnterReadLock();
        try
        {
            return _streamRef;
        }
        finally
        {
            _mu.ExitReadLock();
        }
    }

    internal string StreamName() => GetStream()?.Name ?? string.Empty;

    internal bool IsActive()
    {
        _mu.EnterReadLock();
        try
        {
            return !_closed && (_hasLocalDeliveryInterest || IsPullMode());
        }
        finally
        {
            _mu.ExitReadLock();
        }
    }

    internal bool HasNoLocalInterest() => !HasDeliveryInterest(localInterest: true);

    internal void Purge()
    {
        _mu.EnterWriteLock();
        try
        {
            _state.Pending?.Clear();
            _state.Redelivered?.Clear();
            _redeliveryQueue.Clear();
            _redeliveryIndex.Clear();
            _npc = 0;
        }
        finally
        {
            _mu.ExitWriteLock();
        }
    }

    internal static Timer? StopAndClearTimer(Timer? timer)
    {
        timer?.Dispose();
        return null;
    }

    internal void DeleteWithoutAdvisory() => Stop();
}
