using Microsoft.Extensions.Logging.Abstractions;
using NATS.Server.Configuration;
using NATS.Server.LeafNodes;

namespace NATS.Server.LeafNodes.Tests.LeafNodes;

/// <summary>
/// Unit tests for leaf connection disable flag (Gap 12.7).
/// Verifies that <see cref="LeafNodeManager.IsLeafConnectDisabled"/>,
/// <see cref="LeafNodeManager.DisableLeafConnect"/>, <see cref="LeafNodeManager.EnableLeafConnect"/>,
/// <see cref="LeafNodeManager.DisableAllLeafConnections"/>, and related APIs correctly track
/// per-remote and global disable state.
/// Go reference: leafnode.go isLeafConnectDisabled.
/// </summary>
public class LeafDisableTests
{
    private static LeafNodeManager CreateManager() =>
        new(
            options: new LeafNodeOptions { Host = "127.0.0.1", Port = 0 },
            stats: new ServerStats(),
            serverId: "test-server",
            remoteSubSink: _ => { },
            messageSink: _ => { },
            logger: NullLogger<LeafNodeManager>.Instance);

    // Go: leafnode.go isLeafConnectDisabled — fresh manager has no disabled remotes
    [Fact]
    public void IsLeafConnectDisabled_NotDisabled_ReturnsFalse()
    {
        var manager = CreateManager();

        manager.IsLeafConnectDisabled("nats://127.0.0.1:4222").ShouldBeFalse();
    }

    // Go: leafnode.go isLeafConnectDisabled — per-remote disable recorded
    [Fact]
    public void DisableLeafConnect_ThenIsDisabled_ReturnsTrue()
    {
        var manager = CreateManager();

        manager.DisableLeafConnect("nats://127.0.0.1:4222");

        manager.IsLeafConnectDisabled("nats://127.0.0.1:4222").ShouldBeTrue();
    }

    // Go: leafnode.go isLeafConnectDisabled — re-enable clears disable state
    [Fact]
    public void EnableLeafConnect_AfterDisable_ReturnsFalse()
    {
        var manager = CreateManager();
        manager.DisableLeafConnect("nats://127.0.0.1:4222");

        manager.EnableLeafConnect("nats://127.0.0.1:4222");

        manager.IsLeafConnectDisabled("nats://127.0.0.1:4222").ShouldBeFalse();
    }

    // Go: leafnode.go isLeafConnectDisabled — each remote tracked independently
    [Fact]
    public void DisableLeafConnect_MultipleRemotes_TrackedSeparately()
    {
        var manager = CreateManager();

        manager.DisableLeafConnect("nats://192.168.1.1:4222");
        manager.DisableLeafConnect("nats://192.168.1.2:4222");

        manager.IsLeafConnectDisabled("nats://192.168.1.1:4222").ShouldBeTrue();
        manager.IsLeafConnectDisabled("nats://192.168.1.2:4222").ShouldBeTrue();
        manager.IsLeafConnectDisabled("nats://192.168.1.3:4222").ShouldBeFalse();
    }

    // Go: leafnode.go isLeafConnectDisabled — global flag defaults to false
    [Fact]
    public void IsGloballyDisabled_Default_False()
    {
        var manager = CreateManager();

        manager.IsGloballyDisabled.ShouldBeFalse();
    }

    // Go: leafnode.go isLeafConnectDisabled — DisableAllLeafConnections sets global flag
    [Fact]
    public void DisableAllLeafConnections_DisablesAll()
    {
        var manager = CreateManager();

        manager.DisableAllLeafConnections("test reason");

        manager.IsGloballyDisabled.ShouldBeTrue();
        manager.IsLeafConnectDisabled("nats://127.0.0.1:4222").ShouldBeTrue();
        manager.IsLeafConnectDisabled("nats://10.0.0.1:6222").ShouldBeTrue();
    }

    // Go: leafnode.go isLeafConnectDisabled — EnableAllLeafConnections clears global flag
    [Fact]
    public void EnableAllLeafConnections_ReEnables()
    {
        var manager = CreateManager();
        manager.DisableAllLeafConnections();

        manager.EnableAllLeafConnections();

        manager.IsGloballyDisabled.ShouldBeFalse();
        manager.IsLeafConnectDisabled("nats://127.0.0.1:4222").ShouldBeFalse();
    }

    // Go: leafnode.go isLeafConnectDisabled — global disable overrides non-disabled remote
    [Fact]
    public void IsLeafConnectDisabled_GlobalOverridesPerRemote()
    {
        var manager = CreateManager();
        // Remote is NOT individually disabled — but global disable should still block it.
        manager.DisableAllLeafConnections();

        manager.IsLeafConnectDisabled("nats://127.0.0.1:4222").ShouldBeTrue();
    }

    // Go: leafnode.go isLeafConnectDisabled — GetDisabledRemotes lists all per-remote entries
    [Fact]
    public void GetDisabledRemotes_ReturnsAll()
    {
        var manager = CreateManager();
        manager.DisableLeafConnect("nats://10.0.0.1:4222");
        manager.DisableLeafConnect("nats://10.0.0.2:4222");

        var disabled = manager.GetDisabledRemotes();

        disabled.Count.ShouldBe(2);
        disabled.ShouldContain("nats://10.0.0.1:4222");
        disabled.ShouldContain("nats://10.0.0.2:4222");
    }

    // Go: leafnode.go isLeafConnectDisabled — DisabledRemoteCount matches number of disabled remotes
    [Fact]
    public void DisabledRemoteCount_MatchesDisabled()
    {
        var manager = CreateManager();
        manager.DisabledRemoteCount.ShouldBe(0);

        manager.DisableLeafConnect("nats://10.0.0.1:4222");
        manager.DisabledRemoteCount.ShouldBe(1);

        manager.DisableLeafConnect("nats://10.0.0.2:4222");
        manager.DisabledRemoteCount.ShouldBe(2);

        manager.EnableLeafConnect("nats://10.0.0.1:4222");
        manager.DisabledRemoteCount.ShouldBe(1);
    }
}
