using NATS.Server.JetStream.Cluster;

namespace NATS.Server.JetStream.Tests.JetStream.Cluster;

public class JetStreamLeadershipTests
{
    [Fact]
    public void ProcessLeaderChange_clears_inflight_on_step_down()
    {
        var meta = new JetStreamMetaGroup(3);
        meta.TrackInflightStreamProposal("ACC", new StreamAssignment
        {
            StreamName = "s1",
            Group = new RaftGroup { Name = "rg", Peers = ["n1", "n2", "n3"] },
        });

        meta.ProcessLeaderChange(isLeader: false);

        meta.InflightStreamCount.ShouldBe(0);
    }

    [Fact]
    public void ProcessLeaderChange_fires_event_on_become_leader()
    {
        var meta = new JetStreamMetaGroup(3);
        var leaderChanged = false;
        meta.OnLeaderChange += (isLeader) => leaderChanged = true;

        meta.ProcessLeaderChange(isLeader: true);

        leaderChanged.ShouldBeTrue();
    }

    [Fact]
    public void ProcessLeaderChange_fires_event_on_step_down()
    {
        var meta = new JetStreamMetaGroup(3);
        bool? receivedIsLeader = null;
        meta.OnLeaderChange += (isLeader) => receivedIsLeader = isLeader;

        meta.ProcessLeaderChange(isLeader: false);

        receivedIsLeader.ShouldNotBeNull();
        receivedIsLeader.Value.ShouldBeFalse();
    }

    [Fact]
    public void StepDown_triggers_leader_change_event()
    {
        var meta = new JetStreamMetaGroup(3);
        bool? receivedIsLeader = null;
        meta.OnLeaderChange += (isLeader) => receivedIsLeader = isLeader;

        meta.StepDown();

        receivedIsLeader.ShouldNotBeNull();
        receivedIsLeader.Value.ShouldBeFalse();
    }

    [Fact]
    public void StepDown_clears_inflight_via_process_leader_change()
    {
        var meta = new JetStreamMetaGroup(3);
        meta.TrackInflightStreamProposal("ACC", new StreamAssignment
        {
            StreamName = "s1",
            Group = new RaftGroup { Name = "rg", Peers = ["n1", "n2", "n3"] },
        });
        meta.TrackInflightConsumerProposal("ACC", "s1", "c1");

        meta.StepDown();

        meta.InflightStreamCount.ShouldBe(0);
        meta.InflightConsumerCount.ShouldBe(0);
    }

    [Fact]
    public void BecomeLeader_makes_IsLeader_true()
    {
        var meta = new JetStreamMetaGroup(3);
        meta.StepDown(); // move leader away from self
        meta.IsLeader().ShouldBeFalse();

        meta.BecomeLeader();

        meta.IsLeader().ShouldBeTrue();
    }

    [Fact]
    public void OnLeaderChange_not_fired_when_no_subscribers()
    {
        // Should not throw when no handlers attached
        var meta = new JetStreamMetaGroup(3);
        Should.NotThrow(() => meta.ProcessLeaderChange(isLeader: true));
        Should.NotThrow(() => meta.ProcessLeaderChange(isLeader: false));
    }
}
