// Copyright 2012-2026 The NATS Authors
// Licensed under the Apache License, Version 2.0

using Shouldly;
using NSubstitute;
using ZB.MOM.NatsNet.Server;

namespace ZB.MOM.NatsNet.Server.Tests.JetStream;

public sealed class NatsStreamTests
{
    [Fact]
    public void Create_SetLeader_Purge_AndSeal_ShouldBehave()
    {
        var account = new Account { Name = "A" };
        var streamCfg = new StreamConfig { Name = "ORDERS", Subjects = ["orders.*"], Storage = StorageType.FileStorage };

        var memCfg = streamCfg.Clone();
        memCfg.Storage = StorageType.MemoryStorage;
        var store = new JetStreamMemStore(memCfg);
        store.StoreMsg("orders.new", null, [1, 2], 0);

        var stream = NatsStream.Create(account, streamCfg, null, store, null, null);
        stream.ShouldNotBeNull();

        stream!.IsLeader().ShouldBeFalse();
        stream.SetLeader(true, 7);
        stream.IsLeader().ShouldBeTrue();

        stream.State().Msgs.ShouldBe(1UL);
        stream.Purge();
        stream.State().Msgs.ShouldBe(0UL);

        stream.IsSealed().ShouldBeFalse();
        stream.Seal();
        stream.IsSealed().ShouldBeTrue();

        stream.GetAccount().Name.ShouldBe("A");
        stream.GetInfo().Config.Name.ShouldBe("ORDERS");

        stream.Delete();
        stream.IsLeader().ShouldBeFalse();
    }

    [Fact]
    public void LifecyclePrimitives_AssignmentAndChannels_ShouldBehave()
    {
        var account = new Account { Name = "A" };
        var stream = NatsStream.Create(
            account,
            new StreamConfig { Name = "ORDERS", Subjects = ["orders.*"], Storage = StorageType.MemoryStorage },
            null,
            new JetStreamMemStore(new StreamConfig { Name = "ORDERS", Subjects = ["orders.*"], Storage = StorageType.MemoryStorage }),
            null,
            null)!;

        stream.AccountLocked(true).ShouldBe(account);
        stream.StreamAssignment().ShouldBeNull();

        var assignment = new StreamAssignment { Sync = "sync.inbox" };
        stream.SetStreamAssignment(assignment);
        stream.StreamAssignment().ShouldBe(assignment);

        stream.UpdateC().TryRead(out var updateSignal).ShouldBeTrue();
        updateSignal.ShouldBeTrue();

        stream.StartClusterSubs();
        stream.ClusterSubsActive().ShouldBeTrue();
        stream.StopClusterSubs();
        stream.ClusterSubsActive().ShouldBeFalse();

        var monitor = stream.MonitorQuitC();
        monitor.ShouldNotBeNull();
        stream.SignalMonitorQuit();
        stream.MonitorQuitC().ShouldNotBeNull();
    }

    [Fact]
    public void IsLeaderInternal_WhenAssignedToRaftNode_UsesNodeLeaderState()
    {
        var account = new Account { Name = "A" };
        var stream = NatsStream.Create(
            account,
            new StreamConfig { Name = "ORDERS", Subjects = ["orders.*"], Storage = StorageType.MemoryStorage },
            null,
            new JetStreamMemStore(new StreamConfig { Name = "ORDERS", Subjects = ["orders.*"], Storage = StorageType.MemoryStorage }),
            null,
            null)!;

        var raftNode = Substitute.For<IRaftNode>();
        raftNode.Leader().Returns(false);
        var assignment = new StreamAssignment { Group = new RaftGroup { Node = raftNode } };

        stream.SetStreamAssignment(assignment);

        stream.IsLeaderInternal().ShouldBeFalse();
    }
}
