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

namespace NATS.Server.LeafNodes.Tests.LeafNodes;

/// <summary>
/// Unit tests for leaf cluster topology registration (Gap 12.6).
/// Verifies that <see cref="LeafNodeManager.RegisterLeafNodeCluster"/>,
/// <see cref="LeafNodeManager.UnregisterLeafNodeCluster"/>,
/// <see cref="LeafNodeManager.HasLeafNodeCluster"/>,
/// <see cref="LeafNodeManager.GetLeafNodeCluster"/>,
/// <see cref="LeafNodeManager.GetAllLeafClusters"/>,
/// <see cref="LeafNodeManager.LeafClusterCount"/>, and
/// <see cref="LeafNodeManager.UpdateLeafClusterConnectionCount"/>
/// correctly manage leaf cluster entries.
/// Go reference: leafnode.go registerLeafNodeCluster.
/// </summary>
public class LeafClusterRegistrationTests
{
    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 registerLeafNodeCluster — first registration succeeds
    [Fact]
    public void RegisterLeafNodeCluster_NewCluster_ReturnsTrue()
    {
        var manager = CreateManager();

        var result = manager.RegisterLeafNodeCluster("cluster-A", "nats://gateway:7222", 3);

        result.ShouldBeTrue();
    }

    // Go: leafnode.go registerLeafNodeCluster — duplicate name returns false
    [Fact]
    public void RegisterLeafNodeCluster_Duplicate_ReturnsFalse()
    {
        var manager = CreateManager();
        manager.RegisterLeafNodeCluster("cluster-A", "nats://gateway:7222", 3);

        var result = manager.RegisterLeafNodeCluster("cluster-A", "nats://other:7222", 1);

        result.ShouldBeFalse();
    }

    // Go: leafnode.go — cluster removal for existing entry returns true
    [Fact]
    public void UnregisterLeafNodeCluster_Existing_ReturnsTrue()
    {
        var manager = CreateManager();
        manager.RegisterLeafNodeCluster("cluster-A", "nats://gateway:7222", 3);

        var result = manager.UnregisterLeafNodeCluster("cluster-A");

        result.ShouldBeTrue();
    }

    // Go: leafnode.go — cluster removal for absent entry returns false
    [Fact]
    public void UnregisterLeafNodeCluster_NonExistent_ReturnsFalse()
    {
        var manager = CreateManager();

        var result = manager.UnregisterLeafNodeCluster("cluster-X");

        result.ShouldBeFalse();
    }

    // Go: leafnode.go — HasLeafNodeCluster true after registration
    [Fact]
    public void HasLeafNodeCluster_Registered_ReturnsTrue()
    {
        var manager = CreateManager();
        manager.RegisterLeafNodeCluster("cluster-A", "nats://gateway:7222", 3);

        manager.HasLeafNodeCluster("cluster-A").ShouldBeTrue();
    }

    // Go: leafnode.go — HasLeafNodeCluster false when not registered
    [Fact]
    public void HasLeafNodeCluster_NotRegistered_ReturnsFalse()
    {
        var manager = CreateManager();

        manager.HasLeafNodeCluster("cluster-X").ShouldBeFalse();
    }

    // Go: leafnode.go — GetLeafNodeCluster returns registered info
    [Fact]
    public void GetLeafNodeCluster_Found_ReturnsInfo()
    {
        var manager = CreateManager();
        manager.RegisterLeafNodeCluster("cluster-A", "nats://gateway:7222", 5);

        var info = manager.GetLeafNodeCluster("cluster-A");

        info.ShouldNotBeNull();
        info.ClusterName.ShouldBe("cluster-A");
        info.GatewayUrl.ShouldBe("nats://gateway:7222");
        info.ConnectionCount.ShouldBe(5);
    }

    // Go: leafnode.go — GetLeafNodeCluster returns null for absent cluster
    [Fact]
    public void GetLeafNodeCluster_NotFound_ReturnsNull()
    {
        var manager = CreateManager();

        var info = manager.GetLeafNodeCluster("cluster-X");

        info.ShouldBeNull();
    }

    // Go: leafnode.go — GetAllLeafClusters returns all registered entries
    [Fact]
    public void GetAllLeafClusters_ReturnsAll()
    {
        var manager = CreateManager();
        manager.RegisterLeafNodeCluster("cluster-A", "nats://gw-a:7222", 2);
        manager.RegisterLeafNodeCluster("cluster-B", "nats://gw-b:7222", 4);

        var all = manager.GetAllLeafClusters();

        all.Count.ShouldBe(2);
        all.Select(c => c.ClusterName).ShouldContain("cluster-A");
        all.Select(c => c.ClusterName).ShouldContain("cluster-B");
    }

    // Go: leafnode.go — UpdateLeafClusterConnectionCount updates the count on existing entry
    [Fact]
    public void UpdateLeafClusterConnectionCount_UpdatesCount()
    {
        var manager = CreateManager();
        manager.RegisterLeafNodeCluster("cluster-A", "nats://gateway:7222", 1);

        manager.UpdateLeafClusterConnectionCount("cluster-A", 7);

        var info = manager.GetLeafNodeCluster("cluster-A");
        info.ShouldNotBeNull();
        info.ConnectionCount.ShouldBe(7);
    }
}
