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

namespace NATS.Server.Monitoring.Tests.Events;

public class EventApiAndSubjectsParityBatch2Tests
{
    [Fact]
    public void EventSubjects_DefineMissingServerRequestSubjects()
    {
        EventSubjects.RemoteLatency.ShouldBe("$SYS.SERVER.{0}.ACC.{1}.LATENCY.M2");
        EventSubjects.UserDirectInfo.ShouldBe("$SYS.REQ.USER.INFO");
        EventSubjects.UserDirectReq.ShouldBe("$SYS.REQ.USER.{0}.INFO");
        EventSubjects.AccountNumSubsReq.ShouldBe("$SYS.REQ.ACCOUNT.NSUBS");
        EventSubjects.AccountSubs.ShouldBe("$SYS._INBOX_.{0}.NSUBS");
        EventSubjects.ClientKickReq.ShouldBe("$SYS.REQ.SERVER.{0}.KICK");
        EventSubjects.ClientLdmReq.ShouldBe("$SYS.REQ.SERVER.{0}.LDM");
        EventSubjects.ServerStatsPingReq.ShouldBe("$SYS.REQ.SERVER.PING.STATSZ");
        EventSubjects.ServerReloadReq.ShouldBe("$SYS.REQ.SERVER.{0}.RELOAD");
    }

    [Fact]
    public void OcspSubjects_MatchGoPatterns()
    {
        EventSubjects.OcspPeerReject.ShouldBe("$SYS.SERVER.{0}.OCSP.PEER.CONN.REJECT");
        EventSubjects.OcspPeerChainlinkInvalid.ShouldBe("$SYS.SERVER.{0}.OCSP.PEER.LINK.INVALID");
    }

    [Fact]
    public void OcspPeerRejectEvent_IncludesPeerCertInfo()
    {
        var evt = new OcspPeerRejectEventMsg
        {
            Id = "id",
            Kind = "client",
            Reason = "revoked",
            Peer = new EventCertInfo
            {
                Subject = "CN=client",
                Issuer = "CN=issuer",
                Fingerprint = "fingerprint",
                Raw = "raw",
            },
        };

        var json = JsonSerializer.Serialize(evt);
        json.ShouldContain("\"peer\":");
        json.ShouldContain("\"subject\":\"CN=client\"");
    }

    [Fact]
    public void OcspPeerChainlinkInvalidEvent_SerializesExpectedShape()
    {
        var evt = new OcspPeerChainlinkInvalidEventMsg
        {
            Id = "id",
            Link = new EventCertInfo { Subject = "CN=link" },
            Peer = new EventCertInfo { Subject = "CN=peer" },
        };

        var json = JsonSerializer.Serialize(evt);
        json.ShouldContain("\"type\":\"io.nats.server.advisory.v1.ocsp_peer_link_invalid\"");
        json.ShouldContain("\"link\":");
        json.ShouldContain("\"peer\":");
    }

    [Fact]
    public void EventFilterOptions_HasCoreGoFields()
    {
        var opts = new EventFilterOptions
        {
            Name = "srv-a",
            Cluster = "cluster-a",
            Host = "127.0.0.1",
            Tags = ["a", "b"],
            Domain = "domain-a",
        };

        opts.Name.ShouldBe("srv-a");
        opts.Cluster.ShouldBe("cluster-a");
        opts.Host.ShouldBe("127.0.0.1");
        opts.Tags.ShouldBe(["a", "b"]);
        opts.Domain.ShouldBe("domain-a");
    }

    [Fact]
    public void OptionRequestTypes_IncludeBaseFilterFields()
    {
        new StatszEventOptions { Name = "n" }.Name.ShouldBe("n");
        new ConnzEventOptions { Cluster = "c" }.Cluster.ShouldBe("c");
        new RoutezEventOptions { Host = "h" }.Host.ShouldBe("h");
        new HealthzEventOptions { Domain = "d" }.Domain.ShouldBe("d");
        new JszEventOptions { Tags = ["t"] }.Tags.ShouldBe(["t"]);
    }

    [Fact]
    public void ServerApiResponses_ExposeDataAndError()
    {
        var response = new ServerAPIResponse
        {
            Server = new EventServerInfo { Id = "S1" },
            Data = new { ok = true },
            Error = new ServerAPIError { Code = 500, Description = "err" },
        };

        response.Server.Id.ShouldBe("S1");
        response.Error?.Code.ShouldBe(500);
        response.Error?.Description.ShouldBe("err");
    }

    [Fact]
    public void TypedServerApiWrappers_CarryResponsePayload()
    {
        new ServerAPIConnzResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPIRoutezResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPIGatewayzResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPIJszResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPIHealthzResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPIVarzResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPISubszResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPILeafzResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPIAccountzResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPIExpvarzResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPIpqueueszResponse { Data = new object() }.Data.ShouldNotBeNull();
        new ServerAPIRaftzResponse { Data = new object() }.Data.ShouldNotBeNull();
    }

    [Fact]
    public void RequestPayloadTypes_KickAndLdm()
    {
        var kick = new KickClientReq { ClientId = 22 };
        var ldm = new LDMClientReq { ClientId = 33 };

        kick.ClientId.ShouldBe(22UL);
        ldm.ClientId.ShouldBe(33UL);
    }

    [Fact]
    public void UserInfo_IncludesExpectedIdentityFields()
    {
        var info = new UserInfo
        {
            User = "alice",
            Account = "A",
            Permissions = "pubsub",
        };

        info.User.ShouldBe("alice");
        info.Account.ShouldBe("A");
        info.Permissions.ShouldBe("pubsub");
    }
}
