using System.Text.Json;
using NATS.Server.Events;

namespace NATS.Server.Monitoring.Tests.Events;

/// <summary>
/// Tests for remote server and leaf node event DTOs and subject constants.
/// Go reference: events.go — remote server lifecycle, leaf node advisory subjects.
/// Gap 10.8: RemoteServerShutdown, RemoteServerUpdate, LeafNodeConnected events.
/// </summary>
public class RemoteServerEventTests
{
    // --- RemoteServerShutdownEvent ---

    [Fact]
    public void RemoteServerShutdownEvent_HasCorrectEventType()
    {
        RemoteServerShutdownEvent.EventType.ShouldBe("io.nats.server.advisory.v1.remote_shutdown");
        var ev = new RemoteServerShutdownEvent();
        ev.Type.ShouldBe(RemoteServerShutdownEvent.EventType);
    }

    [Fact]
    public void RemoteServerShutdownEvent_GeneratesUniqueId()
    {
        var ev1 = new RemoteServerShutdownEvent();
        var ev2 = new RemoteServerShutdownEvent();
        ev1.Id.ShouldNotBeNullOrEmpty();
        ev2.Id.ShouldNotBeNullOrEmpty();
        ev1.Id.ShouldNotBe(ev2.Id);
    }

    // --- RemoteServerUpdateEvent ---

    [Fact]
    public void RemoteServerUpdateEvent_HasCorrectEventType()
    {
        RemoteServerUpdateEvent.EventType.ShouldBe("io.nats.server.advisory.v1.remote_update");
        var ev = new RemoteServerUpdateEvent();
        ev.Type.ShouldBe(RemoteServerUpdateEvent.EventType);
    }

    [Fact]
    public void RemoteServerUpdateEvent_AllFieldsSettable()
    {
        var server = new EventServerInfo { Id = "srv1", Name = "my-server" };
        var ev = new RemoteServerUpdateEvent
        {
            Server = server,
            RemoteServerId = "remote-id-123",
            RemoteServerName = "remote-server",
            UpdateType = "routes_changed",
        };

        ev.Server.ShouldBeSameAs(server);
        ev.RemoteServerId.ShouldBe("remote-id-123");
        ev.RemoteServerName.ShouldBe("remote-server");
        ev.UpdateType.ShouldBe("routes_changed");
    }

    // --- LeafNodeConnectEvent ---

    [Fact]
    public void LeafNodeConnectEvent_HasCorrectEventType()
    {
        LeafNodeConnectEvent.EventType.ShouldBe("io.nats.server.advisory.v1.leafnode_connect");
        var ev = new LeafNodeConnectEvent();
        ev.Type.ShouldBe(LeafNodeConnectEvent.EventType);
    }

    [Fact]
    public void LeafNodeConnectEvent_AllFieldsSettable()
    {
        var server = new EventServerInfo { Id = "srv1", Name = "hub" };
        var ev = new LeafNodeConnectEvent
        {
            Server = server,
            LeafNodeId = "leaf-id-abc",
            LeafNodeName = "leaf-node-1",
            RemoteUrl = "nats://10.0.0.1:7422",
            Account = "ACC",
        };

        ev.Server.ShouldBeSameAs(server);
        ev.LeafNodeId.ShouldBe("leaf-id-abc");
        ev.LeafNodeName.ShouldBe("leaf-node-1");
        ev.RemoteUrl.ShouldBe("nats://10.0.0.1:7422");
        ev.Account.ShouldBe("ACC");
    }

    // --- LeafNodeDisconnectEvent ---

    [Fact]
    public void LeafNodeDisconnectEvent_HasCorrectEventType()
    {
        LeafNodeDisconnectEvent.EventType.ShouldBe("io.nats.server.advisory.v1.leafnode_disconnect");
        var ev = new LeafNodeDisconnectEvent();
        ev.Type.ShouldBe(LeafNodeDisconnectEvent.EventType);
    }

    [Fact]
    public void LeafNodeDisconnectEvent_AllFieldsSettable()
    {
        var server = new EventServerInfo { Id = "srv1", Name = "hub" };
        var ev = new LeafNodeDisconnectEvent
        {
            Server = server,
            LeafNodeId = "leaf-id-xyz",
            Reason = "connection closed",
        };

        ev.Server.ShouldBeSameAs(server);
        ev.LeafNodeId.ShouldBe("leaf-id-xyz");
        ev.Reason.ShouldBe("connection closed");
    }

    // --- EventSubjects ---

    [Fact]
    public void EventSubjects_RemoteShutdown_HasPlaceholder()
    {
        EventSubjects.RemoteServerShutdown.ShouldContain("{0}");
        EventSubjects.RemoteServerUpdate.ShouldContain("{0}");
        EventSubjects.LeafNodeConnected.ShouldContain("{0}");
        EventSubjects.LeafNodeDisconnected.ShouldContain("{0}");

        // Verify format strings produce expected subjects when formatted
        var serverId = "ABCDEF123456";
        string.Format(EventSubjects.RemoteServerShutdown, serverId)
            .ShouldBe($"$SYS.SERVER.{serverId}.REMOTE.SHUTDOWN");
        string.Format(EventSubjects.LeafNodeConnected, serverId)
            .ShouldBe($"$SYS.ACCOUNT.{serverId}.LEAFNODE.CONNECT");
    }

    // --- JSON serialization ---

    [Fact]
    public void AllRemoteEvents_SerializeToJson()
    {
        var server = new EventServerInfo { Id = "srv-id", Name = "test-server" };

        var shutdown = new RemoteServerShutdownEvent
        {
            Server = server,
            RemoteServerId = "r1",
            RemoteServerName = "remote",
            Reason = "graceful",
        };
        var shutdownJson = JsonSerializer.Serialize(shutdown);
        var shutdownDoc = JsonDocument.Parse(shutdownJson).RootElement;
        shutdownDoc.GetProperty("type").GetString().ShouldBe(RemoteServerShutdownEvent.EventType);
        shutdownDoc.GetProperty("id").GetString().ShouldNotBeNullOrEmpty();
        shutdownDoc.GetProperty("remote_server_id").GetString().ShouldBe("r1");
        shutdownDoc.GetProperty("reason").GetString().ShouldBe("graceful");

        var update = new RemoteServerUpdateEvent
        {
            Server = server,
            RemoteServerId = "r2",
            RemoteServerName = "remote2",
            UpdateType = "config_updated",
        };
        var updateJson = JsonSerializer.Serialize(update);
        var updateDoc = JsonDocument.Parse(updateJson).RootElement;
        updateDoc.GetProperty("type").GetString().ShouldBe(RemoteServerUpdateEvent.EventType);
        updateDoc.GetProperty("update_type").GetString().ShouldBe("config_updated");

        var connect = new LeafNodeConnectEvent
        {
            Server = server,
            LeafNodeId = "leaf1",
            LeafNodeName = "leaf-node",
            RemoteUrl = "nats://10.0.0.1:7422",
            Account = "ACC",
        };
        var connectJson = JsonSerializer.Serialize(connect);
        var connectDoc = JsonDocument.Parse(connectJson).RootElement;
        connectDoc.GetProperty("type").GetString().ShouldBe(LeafNodeConnectEvent.EventType);
        connectDoc.GetProperty("leaf_node_id").GetString().ShouldBe("leaf1");
        connectDoc.GetProperty("account").GetString().ShouldBe("ACC");

        var disconnect = new LeafNodeDisconnectEvent
        {
            Server = server,
            LeafNodeId = "leaf1",
            Reason = "timeout",
        };
        var disconnectJson = JsonSerializer.Serialize(disconnect);
        var disconnectDoc = JsonDocument.Parse(disconnectJson).RootElement;
        disconnectDoc.GetProperty("type").GetString().ShouldBe(LeafNodeDisconnectEvent.EventType);
        disconnectDoc.GetProperty("leaf_node_id").GetString().ShouldBe("leaf1");
        disconnectDoc.GetProperty("reason").GetString().ShouldBe("timeout");

        // Roundtrip: deserialize back and verify type field survives
        var shutdownRt = JsonSerializer.Deserialize<RemoteServerShutdownEvent>(shutdownJson);
        shutdownRt.ShouldNotBeNull();
        shutdownRt!.Type.ShouldBe(RemoteServerShutdownEvent.EventType);
        shutdownRt.RemoteServerId.ShouldBe("r1");
    }
}
