namespace ZB.MOM.NatsNet.Server;

internal sealed partial class NatsStream
{
    internal Exception? ProcessInboundJetStreamMsg(InMsg? msg)
    {
        if (msg == null)
            return new ArgumentNullException(nameof(msg));

        try
        {
            return ProcessJetStreamMsg(
                msg.Subject,
                msg.Reply ?? string.Empty,
                msg.Hdr,
                msg.Msg,
                lseq: 0,
                ts: 0,
                msgTrace: null,
                sourced: false,
                canRespond: true);
        }
        finally
        {
            msg.ReturnToPool();
        }
    }

    internal Exception? ProcessJetStreamMsg(
        string subject,
        string reply,
        byte[]? hdr,
        byte[]? msg,
        ulong lseq,
        long ts,
        object? msgTrace,
        bool sourced,
        bool canRespond)
    {
        _ = reply;
        _ = msgTrace;
        _ = sourced;
        _ = canRespond;

        if (string.IsNullOrWhiteSpace(subject))
            return new ArgumentException("subject is required", nameof(subject));

        if (Store == null)
            return new InvalidOperationException("store not initialized");

        var batchId = GetBatchId(hdr);
        if (!string.IsNullOrEmpty(batchId))
            return ProcessJetStreamBatchMsg(batchId, subject, reply, hdr, msg, msgTrace);

        try
        {
            var (seq, _) = Store.StoreMsg(subject, hdr, msg, ttl: 0);
            if (lseq > 0)
                seq = lseq;

            if (ts == 0)
                ts = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() * 1_000_000L;

            Interlocked.Exchange(ref LastSeq, (long)seq);
            return null;
        }
        catch (Exception ex)
        {
            return ex;
        }
    }

    internal Exception? ProcessJetStreamBatchMsg(string batchId, string subject, string reply, byte[]? hdr, byte[]? msg, object? msgTrace)
    {
        _ = reply;
        _ = msgTrace;

        if (string.IsNullOrWhiteSpace(batchId))
            return new InvalidOperationException(JsApiErrors.NewJSAtomicPublishInvalidBatchIDError().ToString());

        var (_, exists) = GetBatchSequence(hdr);
        if (!exists)
            return new InvalidOperationException(JsApiErrors.NewJSAtomicPublishMissingSeqError().ToString());

        if (Store == null)
            return new InvalidOperationException("store not initialized");

        try
        {
            Store.StoreMsg(subject, hdr, msg, ttl: 0);
            return null;
        }
        catch (Exception ex)
        {
            return ex;
        }
    }
}
