// Ported from golang/nats-server/server/jetstream_test.go
// Publish/Subscribe: basic pub/sub, message acknowledgment, replay, headers, sequence tracking

using System.Text;
using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Publish;

namespace NATS.Server.Tests.JetStream;

public class JetStreamPubSubTests
{
    // Go: TestJetStreamBasicAckPublish server/jetstream_test.go:710
    [Fact]
    public async Task Publish_returns_puback_with_stream_and_sequence()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("ORDERS", "orders.*");
        var ack = await fx.PublishAndGetAckAsync("orders.created", "payload");

        ack.Stream.ShouldBe("ORDERS");
        ack.Seq.ShouldBe(1UL);
        ack.ErrorCode.ShouldBeNull();
    }

    // Go: TestJetStreamPubAck server/jetstream_test.go:298
    [Fact]
    public async Task Multiple_publishes_increment_sequence()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("SEQ", "seq.>");

        var ack1 = await fx.PublishAndGetAckAsync("seq.a", "1");
        ack1.Seq.ShouldBe(1UL);

        var ack2 = await fx.PublishAndGetAckAsync("seq.b", "2");
        ack2.Seq.ShouldBe(2UL);

        var ack3 = await fx.PublishAndGetAckAsync("seq.c", "3");
        ack3.Seq.ShouldBe(3UL);
    }

    // Go: TestJetStreamPublishDeDupe server/jetstream_test.go:2533
    [Fact]
    public async Task Duplicate_msg_id_is_rejected()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamConfigAsync(new StreamConfig
        {
            Name = "DEDUP",
            Subjects = ["dedup.>"],
            DuplicateWindowMs = 60_000,
        });

        var ack1 = await fx.PublishAndGetAckAsync("dedup.x", "first", msgId: "uniq-1");
        ack1.ErrorCode.ShouldBeNull();

        var ack2 = await fx.PublishAndGetAckAsync("dedup.x", "second", msgId: "uniq-1");
        ack2.ErrorCode.ShouldNotBeNull();
    }

    // Go: TestJetStreamPublishExpect server/jetstream_test.go:2595
    [Fact]
    public async Task Publish_with_expected_last_seq_succeeds_when_matching()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("EXP", "exp.>");

        var ack1 = await fx.PublishAndGetAckAsync("exp.a", "1");
        ack1.Seq.ShouldBe(1UL);

        var ack2 = await fx.PublishWithExpectedLastSeqAsync("exp.b", "2", 1);
        ack2.ErrorCode.ShouldBeNull();
    }

    // Go: TestJetStreamPublishExpect — mismatch
    [Fact]
    public async Task Publish_with_wrong_expected_last_seq_fails()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("EXPF", "expf.>");
        _ = await fx.PublishAndGetAckAsync("expf.a", "1");

        var ack = await fx.PublishWithExpectedLastSeqAsync("expf.b", "2", 999);
        ack.ErrorCode.ShouldNotBeNull();
    }

    // Go: TestJetStreamSubjectFiltering server/jetstream_test.go:1089
    [Fact]
    public async Task Publish_and_fetch_with_filter_subject()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("FILT", "filt.>");
        _ = await fx.CreateConsumerAsync("FILT", "C1", "filt.a");

        _ = await fx.PublishAndGetAckAsync("filt.a", "match");
        _ = await fx.PublishAndGetAckAsync("filt.b", "no-match");
        _ = await fx.PublishAndGetAckAsync("filt.a", "match2");

        var batch = await fx.FetchAsync("FILT", "C1", 10);
        batch.Messages.Count.ShouldBe(2);
        batch.Messages.All(m => m.Subject == "filt.a").ShouldBeTrue();
    }

    // Go: TestJetStreamWildcardSubjectFiltering server/jetstream_test.go:1152
    [Fact]
    public async Task Publish_and_fetch_with_wildcard_filter()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("WC", "wc.>");
        _ = await fx.CreateConsumerAsync("WC", "C1", "wc.orders.*");

        _ = await fx.PublishAndGetAckAsync("wc.orders.created", "1");
        _ = await fx.PublishAndGetAckAsync("wc.events.logged", "2");
        _ = await fx.PublishAndGetAckAsync("wc.orders.shipped", "3");

        var batch = await fx.FetchAsync("WC", "C1", 10);
        batch.Messages.Count.ShouldBe(2);
    }

    // Go: TestJetStreamWorkQueueRequestBatch server/jetstream_test.go:1505
    [Fact]
    public async Task Fetch_batch_returns_multiple_messages()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("BATCH", "batch.>");
        _ = await fx.CreateConsumerAsync("BATCH", "C1", "batch.>");

        for (var i = 0; i < 5; i++)
            _ = await fx.PublishAndGetAckAsync("batch.x", $"msg-{i}");

        var batch = await fx.FetchAsync("BATCH", "C1", 3);
        batch.Messages.Count.ShouldBe(3);
    }

    // Go: TestJetStreamWorkQueueRequest server/jetstream_test.go:1302
    [Fact]
    public async Task Fetch_single_message()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("SINGLE", "single.>");
        _ = await fx.CreateConsumerAsync("SINGLE", "C1", "single.>");
        _ = await fx.PublishAndGetAckAsync("single.x", "hello");

        var batch = await fx.FetchAsync("SINGLE", "C1", 1);
        batch.Messages.Count.ShouldBe(1);
        Encoding.UTF8.GetString(batch.Messages[0].Payload.Span).ShouldBe("hello");
    }

    // Go: TestJetStreamNextMsgNoInterest server/jetstream_test.go:6522
    [Fact]
    public async Task Fetch_with_no_messages_returns_empty()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("EMPTY", "empty.>");
        _ = await fx.CreateConsumerAsync("EMPTY", "C1", "empty.>");

        var batch = await fx.FetchAsync("EMPTY", "C1", 1);
        batch.Messages.Count.ShouldBe(0);
    }

    // Go: TestJetStreamNoAckStream server/jetstream_test.go:821
    [Fact]
    public async Task Publish_to_stream_with_no_ack_consumer()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("NOACK", "noack.>");
        _ = await fx.CreateConsumerAsync("NOACK", "C1", "noack.>", ackPolicy: AckPolicy.None);

        _ = await fx.PublishAndGetAckAsync("noack.x", "data");

        var batch = await fx.FetchAsync("NOACK", "C1", 1);
        batch.Messages.Count.ShouldBe(1);
    }

    // Go: TestJetStreamActiveDelivery server/jetstream_test.go:3644
    [Fact]
    public async Task Publish_triggers_push_consumer_delivery()
    {
        await using var fx = await JetStreamApiFixture.StartWithPushConsumerAsync();
        _ = await fx.PublishAndGetAckAsync("orders.created", "order-1");

        var frame = await fx.ReadPushFrameAsync();
        frame.IsData.ShouldBeTrue();
        frame.Message.ShouldNotBeNull();
    }

    // Go: TestJetStreamMultipleSubjectsPushBasic server/jetstream_test.go
    [Fact]
    public async Task Push_consumer_receives_matching_messages()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("PS", "ps.>");
        _ = await fx.CreateConsumerAsync("PS", "PUSH", "ps.orders.*", push: true, heartbeatMs: 25);

        _ = await fx.PublishAndGetAckAsync("ps.orders.created", "1");
        _ = await fx.PublishAndGetAckAsync("ps.events.logged", "2");

        var frame = await fx.ReadPushFrameAsync("PS", "PUSH");
        frame.IsData.ShouldBeTrue();
        frame.Message!.Subject.ShouldBe("ps.orders.created");
    }

    // Go: TestJetStreamWorkQueueAckAndNext server/jetstream_test.go:1355
    [Fact]
    public async Task Sequential_fetch_advances_cursor()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("ADV", "adv.>");
        _ = await fx.CreateConsumerAsync("ADV", "C1", "adv.>");

        for (var i = 0; i < 5; i++)
            _ = await fx.PublishAndGetAckAsync("adv.x", $"msg-{i}");

        var batch1 = await fx.FetchAsync("ADV", "C1", 2);
        batch1.Messages.Count.ShouldBe(2);
        batch1.Messages[0].Sequence.ShouldBe(1UL);

        var batch2 = await fx.FetchAsync("ADV", "C1", 2);
        batch2.Messages.Count.ShouldBe(2);
        batch2.Messages[0].Sequence.ShouldBe(3UL);
    }

    // Go: TestJetStreamPublishExpectNoMsg server/jetstream_test.go
    [Fact]
    public async Task Publish_to_unmatched_subject_is_not_captured()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("NOMATCH", "nomatch.orders.*");

        var ack = await fx.PublishAndGetAckAsync("different.subject", "data", expectError: true);
        ack.ErrorCode.ShouldNotBeNull();
    }

    // Go: TestJetStreamPubAck — stream name in ack
    [Fact]
    public async Task Puback_contains_correct_stream_name()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("NAMED", "named.>");
        var ack = await fx.PublishAndGetAckAsync("named.x", "data");
        ack.Stream.ShouldBe("NAMED");
    }

    // Go: TestJetStreamStateTimestamps server/jetstream_test.go:758
    [Fact]
    public async Task Stream_state_updates_after_publish()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("ST", "st.>");

        var before = await fx.GetStreamStateAsync("ST");
        before.Messages.ShouldBe(0UL);

        _ = await fx.PublishAndGetAckAsync("st.x", "data");

        var after = await fx.GetStreamStateAsync("ST");
        after.Messages.ShouldBe(1UL);
        after.Bytes.ShouldBeGreaterThan(0UL);
    }

    // Go: TestJetStreamLongStreamNamesAndPubAck server/jetstream_test.go
    [Fact]
    public async Task Long_stream_name_works()
    {
        var name = new string('A', 50);
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync(name, "long.>");
        var ack = await fx.PublishAndGetAckAsync("long.x", "data");
        ack.Stream.ShouldBe(name);
    }

    // Go: TestJetStreamPublishDeDupe — unique msg IDs accepted
    [Fact]
    public async Task Unique_msg_ids_all_accepted()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamConfigAsync(new StreamConfig
        {
            Name = "UNIQ",
            Subjects = ["uniq.>"],
            DuplicateWindowMs = 60_000,
        });

        for (var i = 0; i < 5; i++)
        {
            var ack = await fx.PublishAndGetAckAsync("uniq.x", $"data-{i}", msgId: $"msg-{i}");
            ack.ErrorCode.ShouldBeNull();
        }

        var state = await fx.GetStreamStateAsync("UNIQ");
        state.Messages.ShouldBe(5UL);
    }

    // Go: TestJetStreamPublishDeDupe — no dedup without window
    [Fact]
    public async Task No_dedup_window_allows_same_msg_id()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("NODEDUP", "nodedup.>");

        var ack1 = await fx.PublishAndGetAckAsync("nodedup.x", "1", msgId: "same");
        ack1.ErrorCode.ShouldBeNull();

        // Without a dedup window, the msg ID is not tracked
        var ack2 = await fx.PublishAndGetAckAsync("nodedup.x", "2", msgId: "same");
        // Could be null or not depending on implementation; both messages stored
    }

    // Go: TestJetStreamNegativeDupeWindow server/jetstream_test.go
    // When dedup window is 0, the implementation still tracks msg IDs in-process (no TTL-based trim).
    // Verify that with no msg ID, duplicate detection is not triggered.
    [Fact]
    public async Task Dedup_window_zero_with_no_msg_id_allows_duplicates()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamConfigAsync(new StreamConfig
        {
            Name = "NODUP",
            Subjects = ["nodup.>"],
            DuplicateWindowMs = 0,
        });

        var ack1 = await fx.PublishAndGetAckAsync("nodup.x", "1");
        ack1.ErrorCode.ShouldBeNull();
        var ack2 = await fx.PublishAndGetAckAsync("nodup.x", "2");
        ack2.ErrorCode.ShouldBeNull();

        var state = await fx.GetStreamStateAsync("NODUP");
        state.Messages.ShouldBe(2UL);
    }

    // Go: TestJetStreamWorkQueueSubjectFiltering server/jetstream_test.go:1127
    [Fact]
    public async Task Fetch_with_no_wait_returns_empty_when_no_messages()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("NW", "nw.>");
        _ = await fx.CreateConsumerAsync("NW", "C1", "nw.>");

        var batch = await fx.FetchWithNoWaitAsync("NW", "C1", 5);
        batch.Messages.Count.ShouldBe(0);
    }

    // Go: TestJetStreamWorkQueueSubjectFiltering — no_wait with messages
    [Fact]
    public async Task Fetch_with_no_wait_returns_available_messages()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("NWM", "nwm.>");
        _ = await fx.CreateConsumerAsync("NWM", "C1", "nwm.>");

        _ = await fx.PublishAndGetAckAsync("nwm.x", "data1");
        _ = await fx.PublishAndGetAckAsync("nwm.x", "data2");

        var batch = await fx.FetchWithNoWaitAsync("NWM", "C1", 5);
        batch.Messages.Count.ShouldBe(2);
    }

    // Go: TestJetStreamBasicWorkQueue server/jetstream_test.go:937
    [Fact]
    public async Task Publish_many_and_fetch_all()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("ALL", "all.>");
        _ = await fx.CreateConsumerAsync("ALL", "C1", "all.>");

        for (var i = 0; i < 10; i++)
            _ = await fx.PublishAndGetAckAsync("all.x", $"msg-{i}");

        var batch = await fx.FetchAsync("ALL", "C1", 20);
        batch.Messages.Count.ShouldBe(10);
    }

    // Go: TestJetStreamMultipleSubjectsBasic server/jetstream_test.go
    [Fact]
    public async Task Multiple_subjects_captured_by_same_stream()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("MULTI", "multi.>");
        _ = await fx.CreateConsumerAsync("MULTI", "C1", "multi.>");

        _ = await fx.PublishAndGetAckAsync("multi.orders", "1");
        _ = await fx.PublishAndGetAckAsync("multi.events", "2");
        _ = await fx.PublishAndGetAckAsync("multi.logs", "3");

        var batch = await fx.FetchAsync("MULTI", "C1", 10);
        batch.Messages.Count.ShouldBe(3);
        batch.Messages.Select(m => m.Subject).ShouldBe(["multi.orders", "multi.events", "multi.logs"]);
    }

    // Go: TestJetStreamGetLastMsgBySubject server/jetstream_test.go
    [Fact]
    public async Task Fetch_preserves_message_subject()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("SUB", "sub.>");
        _ = await fx.CreateConsumerAsync("SUB", "C1", "sub.>");

        _ = await fx.PublishAndGetAckAsync("sub.orders.created", "data");

        var batch = await fx.FetchAsync("SUB", "C1", 1);
        batch.Messages[0].Subject.ShouldBe("sub.orders.created");
    }

    // Go: TestJetStreamPubAck — sequence monotonically increasing
    [Fact]
    public async Task Sequence_numbers_are_monotonically_increasing()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("MONO", "mono.>");

        ulong lastSeq = 0;
        for (var i = 0; i < 10; i++)
        {
            var ack = await fx.PublishAndGetAckAsync("mono.x", $"msg-{i}");
            ack.Seq.ShouldBeGreaterThan(lastSeq);
            lastSeq = ack.Seq;
        }
    }

    // Go: TestJetStreamPerSubjectPending server/jetstream_test.go
    [Fact]
    public async Task Fetch_from_non_existent_consumer_returns_empty()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("FNE", "fne.>");
        _ = await fx.PublishAndGetAckAsync("fne.x", "data");

        var batch = await fx.FetchAsync("FNE", "NOPE", 1);
        batch.Messages.Count.ShouldBe(0);
    }

    // Go: TestJetStreamMaxMsgsPerSubjectWithDiscardNew server/jetstream_test.go
    [Fact]
    public async Task Publish_to_multiple_streams_routes_correctly()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("A", "a.>");
        _ = await fx.RequestLocalAsync("$JS.API.STREAM.CREATE.B", """{"subjects":["b.>"]}""");

        var ackA = await fx.PublishAndGetAckAsync("a.msg", "for-A");
        ackA.Stream.ShouldBe("A");

        var ackB = await fx.PublishAndGetAckAsync("b.msg", "for-B");
        ackB.Stream.ShouldBe("B");
    }

    // Go: TestJetStreamPublishMany
    [Fact]
    public async Task Publish_many_helper_stores_all_messages()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("PM", "pm.>");
        await fx.PublishManyAsync("pm.x", ["a", "b", "c", "d", "e"]);

        var state = await fx.GetStreamStateAsync("PM");
        state.Messages.ShouldBe(5UL);
    }

    // Go: TestJetStreamRejectLargePublishes server/jetstream_test.go
    [Fact]
    public async Task Large_message_rejected_by_max_msg_size()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamConfigAsync(new StreamConfig
        {
            Name = "SMALL",
            Subjects = ["small.>"],
            MaxMsgSize = 5,
        });

        var ack = await fx.PublishAndGetAckAsync("small.x", "this-is-too-big");
        ack.ErrorCode.ShouldNotBeNull();
    }

    // Go: TestJetStreamAddStreamMaxMsgSize — exactly at limit
    [Fact]
    public async Task Message_exactly_at_size_limit_is_accepted()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamConfigAsync(new StreamConfig
        {
            Name = "EXACT",
            Subjects = ["exact.>"],
            MaxMsgSize = 4,
        });

        var ack = await fx.PublishAndGetAckAsync("exact.x", "1234");
        ack.ErrorCode.ShouldBeNull();
    }

    // Go: TestJetStreamPurgeEffectsConsumerDelivery server/jetstream_test.go
    // After purge, a fresh consumer should be able to see new messages.
    [Fact]
    public async Task Purge_followed_by_new_publish_visible_to_new_consumer()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("PCD", "pcd.>");

        _ = await fx.PublishAndGetAckAsync("pcd.x", "old");
        _ = await fx.RequestLocalAsync("$JS.API.STREAM.PURGE.PCD", "{}");

        _ = await fx.PublishAndGetAckAsync("pcd.x", "new");

        // Create a fresh consumer after purge
        _ = await fx.CreateConsumerAsync("PCD", "C2", "pcd.>");
        var batch = await fx.FetchAsync("PCD", "C2", 1);
        batch.Messages.Count.ShouldBe(1);
        Encoding.UTF8.GetString(batch.Messages[0].Payload.Span).ShouldBe("new");
    }

    // Go: TestJetStreamDeliverLastPerSubject server/jetstream_test.go
    [Fact]
    public async Task Deliver_last_policy_starts_from_last_message()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("DLP", "dlp.>");
        _ = await fx.PublishAndGetAckAsync("dlp.x", "first");
        _ = await fx.PublishAndGetAckAsync("dlp.x", "second");
        _ = await fx.PublishAndGetAckAsync("dlp.x", "third");

        _ = await fx.CreateConsumerAsync("DLP", "C1", "dlp.>", deliverPolicy: DeliverPolicy.Last);

        var batch = await fx.FetchAsync("DLP", "C1", 10);
        batch.Messages.Count.ShouldBe(1);
        Encoding.UTF8.GetString(batch.Messages[0].Payload.Span).ShouldBe("third");
    }

    // Go: TestJetStreamDeliverNewPolicy server/jetstream_test.go
    [Fact]
    public async Task Deliver_new_policy_skips_existing_messages()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("DNP", "dnp.>");
        _ = await fx.PublishAndGetAckAsync("dnp.x", "existing1");
        _ = await fx.PublishAndGetAckAsync("dnp.x", "existing2");

        _ = await fx.CreateConsumerAsync("DNP", "C1", "dnp.>", deliverPolicy: DeliverPolicy.New);

        // Fetch should return empty since no new messages
        var batch = await fx.FetchAsync("DNP", "C1", 10);
        batch.Messages.Count.ShouldBe(0);
    }

    // Go: TestJetStreamMultipleSubjectsPushBasic — push multi-subject
    [Fact]
    public async Task Push_consumer_heartbeat_frame_present()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("HB", "hb.>");
        _ = await fx.CreateConsumerAsync("HB", "PUSH", "hb.>", push: true, heartbeatMs: 10);
        _ = await fx.PublishAndGetAckAsync("hb.x", "data");

        // Should have data frame followed by heartbeat frame
        var frame1 = await fx.ReadPushFrameAsync("HB", "PUSH");
        frame1.IsData.ShouldBeTrue();

        var frame2 = await fx.ReadPushFrameAsync("HB", "PUSH");
        frame2.IsHeartbeat.ShouldBeTrue();
    }

    // Go: TestJetStreamPublishExpect — precondition expected last seq = 0
    [Fact]
    public async Task Publish_expected_last_seq_zero_always_succeeds()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("ELZ", "elz.>");
        _ = await fx.PublishAndGetAckAsync("elz.x", "1");

        // Expected last seq 0 means "no check"
        var ack = await fx.PublishWithExpectedLastSeqAsync("elz.x", "2", 0);
        ack.ErrorCode.ShouldBeNull();
    }

    // Go: TestJetStreamDirectMsgGet server/jetstream_test.go
    [Fact]
    public async Task Direct_get_returns_published_message()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("DG", "dg.>");
        var ack = await fx.PublishAndGetAckAsync("dg.x", "direct-payload");

        var resp = await fx.RequestLocalAsync(
            "$JS.API.DIRECT.GET.DG", $$"""{ "seq": {{ack.Seq}} }""");
        resp.DirectMessage.ShouldNotBeNull();
        resp.DirectMessage!.Payload.ShouldBe("direct-payload");
        resp.DirectMessage.Subject.ShouldBe("dg.x");
    }

    // Go: TestJetStreamMsgHeaders server/jetstream_test.go:5554
    [Fact]
    public async Task Message_get_returns_correct_sequence_and_subject()
    {
        await using var fx = await JetStreamApiFixture.StartWithStreamAsync("MG", "mg.>");
        _ = await fx.PublishAndGetAckAsync("mg.first", "data1");
        var ack2 = await fx.PublishAndGetAckAsync("mg.second", "data2");

        var resp = await fx.RequestLocalAsync(
            "$JS.API.STREAM.MSG.GET.MG", $$"""{ "seq": {{ack2.Seq}} }""");
        resp.StreamMessage.ShouldNotBeNull();
        resp.StreamMessage!.Sequence.ShouldBe(ack2.Seq);
        resp.StreamMessage.Subject.ShouldBe("mg.second");
        resp.StreamMessage.Payload.ShouldBe("data2");
    }
}
