using System.Text.Json.Serialization;

namespace NATS.Server.Events;

/// <summary>
/// Server identity block embedded in all system events.
/// Go reference: events.go:249-265 ServerInfo struct.
/// </summary>
public sealed class EventServerInfo
{
    [JsonPropertyName("name")]
    public string Name { get; set; } = string.Empty;

    [JsonPropertyName("host")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Host { get; set; }

    [JsonPropertyName("id")]
    public string Id { get; set; } = string.Empty;

    [JsonPropertyName("cluster")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Cluster { get; set; }

    [JsonPropertyName("domain")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Domain { get; set; }

    [JsonPropertyName("ver")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Version { get; set; }

    [JsonPropertyName("tags")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string[]? Tags { get; set; }

    [JsonPropertyName("metadata")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public Dictionary<string, string>? Metadata { get; set; }

    [JsonPropertyName("jetstream")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public bool JetStream { get; set; }

    [JsonPropertyName("flags")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public ulong Flags { get; set; }

    [JsonPropertyName("seq")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public ulong Seq { get; set; }

    [JsonPropertyName("time")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public DateTime Time { get; set; }
}

/// <summary>
/// Client identity block for connect/disconnect events.
/// Go reference: events.go:308-331 ClientInfo struct.
/// </summary>
public sealed class EventClientInfo
{
    [JsonPropertyName("start")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public DateTime Start { get; set; }

    [JsonPropertyName("stop")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public DateTime Stop { get; set; }

    [JsonPropertyName("host")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Host { get; set; }

    [JsonPropertyName("id")]
    public ulong Id { get; set; }

    [JsonPropertyName("acc")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Account { get; set; }

    [JsonPropertyName("svc")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Service { get; set; }

    [JsonPropertyName("user")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? User { get; set; }

    [JsonPropertyName("name")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Name { get; set; }

    [JsonPropertyName("lang")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Lang { get; set; }

    [JsonPropertyName("ver")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Version { get; set; }

    [JsonPropertyName("rtt")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public long RttNanos { get; set; }

    [JsonPropertyName("server")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Server { get; set; }

    [JsonPropertyName("cluster")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Cluster { get; set; }

    [JsonPropertyName("alts")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string[]? Alternates { get; set; }

    [JsonPropertyName("jwt")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Jwt { get; set; }

    [JsonPropertyName("issuer_key")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? IssuerKey { get; set; }

    [JsonPropertyName("name_tag")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? NameTag { get; set; }

    [JsonPropertyName("tags")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string[]? Tags { get; set; }

    [JsonPropertyName("kind")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Kind { get; set; }

    [JsonPropertyName("client_type")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? ClientType { get; set; }

    [JsonPropertyName("client_id")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? MqttClient { get; set; }

    [JsonPropertyName("nonce")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Nonce { get; set; }
}

/// <summary>
/// Message and byte count stats. Applicable for both sent and received.
/// Go reference: events.go:407-410 MsgBytes, events.go:412-418 DataStats.
/// </summary>
public sealed class DataStats
{
    [JsonPropertyName("msgs")]
    public long Msgs { get; set; }

    [JsonPropertyName("bytes")]
    public long Bytes { get; set; }

    [JsonPropertyName("gateways")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public MsgBytesStats? Gateways { get; set; }

    [JsonPropertyName("routes")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public MsgBytesStats? Routes { get; set; }

    [JsonPropertyName("leafs")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public MsgBytesStats? Leafs { get; set; }
}

/// <summary>
/// Sub-stats for gateway/route/leaf message flow.
/// Go reference: events.go:407-410 MsgBytes.
/// </summary>
public sealed class MsgBytesStats
{
    [JsonPropertyName("msgs")]
    public long Msgs { get; set; }

    [JsonPropertyName("bytes")]
    public long Bytes { get; set; }
}

/// <summary>Client connect advisory. Go events.go:155-160.</summary>
public sealed class ConnectEventMsg
{
    public const string EventType = "io.nats.server.advisory.v1.client_connect";

    [JsonPropertyName("type")]
    public string Type { get; set; } = EventType;

    [JsonPropertyName("id")]
    public string Id { get; set; } = string.Empty;

    [JsonPropertyName("timestamp")]
    public DateTime Time { get; set; }

    [JsonPropertyName("server")]
    public EventServerInfo Server { get; set; } = new();

    [JsonPropertyName("client")]
    public EventClientInfo Client { get; set; } = new();
}

/// <summary>Client disconnect advisory. Go events.go:167-174.</summary>
public sealed class DisconnectEventMsg
{
    public const string EventType = "io.nats.server.advisory.v1.client_disconnect";

    [JsonPropertyName("type")]
    public string Type { get; set; } = EventType;

    [JsonPropertyName("id")]
    public string Id { get; set; } = string.Empty;

    [JsonPropertyName("timestamp")]
    public DateTime Time { get; set; }

    [JsonPropertyName("server")]
    public EventServerInfo Server { get; set; } = new();

    [JsonPropertyName("client")]
    public EventClientInfo Client { get; set; } = new();

    [JsonPropertyName("sent")]
    public DataStats Sent { get; set; } = new();

    [JsonPropertyName("received")]
    public DataStats Received { get; set; } = new();

    [JsonPropertyName("reason")]
    public string Reason { get; set; } = string.Empty;
}

/// <summary>
/// Account connection count heartbeat. Go events.go:210-214, 217-227.
/// Includes the full AccountStat fields from Go.
/// </summary>
public sealed class AccountNumConns
{
    public const string EventType = "io.nats.server.advisory.v1.account_connections";

    [JsonPropertyName("type")]
    public string Type { get; set; } = EventType;

    [JsonPropertyName("id")]
    public string Id { get; set; } = string.Empty;

    [JsonPropertyName("timestamp")]
    public DateTime Time { get; set; }

    [JsonPropertyName("server")]
    public EventServerInfo Server { get; set; } = new();

    /// <summary>Account identifier. Go AccountStat.Account.</summary>
    [JsonPropertyName("acc")]
    public string AccountName { get; set; } = string.Empty;

    /// <summary>Account display name. Go AccountStat.Name.</summary>
    [JsonPropertyName("name")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Name { get; set; }

    /// <summary>Current active connections. Go AccountStat.Conns.</summary>
    [JsonPropertyName("conns")]
    public int Connections { get; set; }

    /// <summary>Active leaf node connections. Go AccountStat.LeafNodes.</summary>
    [JsonPropertyName("leafnodes")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public int LeafNodes { get; set; }

    /// <summary>Total connections over time. Go AccountStat.TotalConns.</summary>
    [JsonPropertyName("total_conns")]
    public int TotalConnections { get; set; }

    /// <summary>Active subscription count. Go AccountStat.NumSubs.</summary>
    [JsonPropertyName("num_subscriptions")]
    public uint NumSubscriptions { get; set; }

    [JsonPropertyName("sent")]
    public DataStats Sent { get; set; } = new();

    [JsonPropertyName("received")]
    public DataStats Received { get; set; } = new();

    /// <summary>Slow consumer count. Go AccountStat.SlowConsumers.</summary>
    [JsonPropertyName("slow_consumers")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public long SlowConsumers { get; set; }
}

/// <summary>
/// Route statistics for server stats broadcast.
/// Go reference: events.go:390-396 RouteStat.
/// </summary>
public sealed class RouteStat
{
    [JsonPropertyName("rid")]
    public ulong Id { get; set; }

    [JsonPropertyName("name")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Name { get; set; }

    [JsonPropertyName("sent")]
    public DataStats Sent { get; set; } = new();

    [JsonPropertyName("received")]
    public DataStats Received { get; set; } = new();

    [JsonPropertyName("pending")]
    public int Pending { get; set; }
}

/// <summary>
/// Gateway statistics for server stats broadcast.
/// Go reference: events.go:399-405 GatewayStat.
/// </summary>
public sealed class GatewayStat
{
    [JsonPropertyName("gwid")]
    public ulong Id { get; set; }

    [JsonPropertyName("name")]
    public string Name { get; set; } = "";

    [JsonPropertyName("sent")]
    public DataStats Sent { get; set; } = new();

    [JsonPropertyName("received")]
    public DataStats Received { get; set; } = new();

    [JsonPropertyName("inbound_connections")]
    public int InboundConnections { get; set; }
}

/// <summary>
/// Slow consumer breakdown statistics.
/// Go reference: events.go:377 SlowConsumersStats.
/// </summary>
public sealed class SlowConsumersStats
{
    [JsonPropertyName("clients")]
    public long Clients { get; set; }

    [JsonPropertyName("routes")]
    public long Routes { get; set; }

    [JsonPropertyName("gateways")]
    public long Gateways { get; set; }

    [JsonPropertyName("leafs")]
    public long Leafs { get; set; }
}

/// <summary>
/// Stale connection breakdown statistics.
/// Go reference: events.go:379 StaleConnectionStats.
/// </summary>
public sealed class StaleConnectionStats
{
    [JsonPropertyName("clients")]
    public long Clients { get; set; }

    [JsonPropertyName("routes")]
    public long Routes { get; set; }

    [JsonPropertyName("gateways")]
    public long Gateways { get; set; }

    [JsonPropertyName("leafs")]
    public long Leafs { get; set; }
}

/// <summary>Server stats broadcast. Go events.go:150-153.</summary>
public sealed class ServerStatsMsg
{
    [JsonPropertyName("server")]
    public EventServerInfo Server { get; set; } = new();

    [JsonPropertyName("statsz")]
    public ServerStatsData Stats { get; set; } = new();
}

/// <summary>
/// Server stats data. Full parity with Go events.go:365-387 ServerStats.
/// </summary>
public sealed class ServerStatsData
{
    [JsonPropertyName("start")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public DateTime Start { get; set; }

    [JsonPropertyName("mem")]
    public long Mem { get; set; }

    [JsonPropertyName("cores")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public int Cores { get; set; }

    [JsonPropertyName("cpu")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public double Cpu { get; set; }

    [JsonPropertyName("connections")]
    public int Connections { get; set; }

    [JsonPropertyName("total_connections")]
    public long TotalConnections { get; set; }

    [JsonPropertyName("active_accounts")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public int ActiveAccounts { get; set; }

    [JsonPropertyName("subscriptions")]
    public long Subscriptions { get; set; }

    /// <summary>Sent stats (msgs + bytes). Go ServerStats.Sent.</summary>
    [JsonPropertyName("sent")]
    public DataStats Sent { get; set; } = new();

    /// <summary>Received stats (msgs + bytes). Go ServerStats.Received.</summary>
    [JsonPropertyName("received")]
    public DataStats Received { get; set; } = new();

    [JsonPropertyName("slow_consumers")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public long SlowConsumers { get; set; }

    [JsonPropertyName("slow_consumer_stats")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public SlowConsumersStats? SlowConsumerStats { get; set; }

    [JsonPropertyName("stale_connections")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public long StaleConnections { get; set; }

    [JsonPropertyName("stale_connection_stats")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public StaleConnectionStats? StaleConnectionStats { get; set; }

    [JsonPropertyName("routes")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public RouteStat[]? Routes { get; set; }

    [JsonPropertyName("gateways")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public GatewayStat[]? Gateways { get; set; }

    [JsonPropertyName("active_servers")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public int ActiveServers { get; set; }

    // Kept for backward compat — flat counters that mirror Sent/Received.
    [JsonPropertyName("in_msgs")]
    public long InMsgs { get; set; }

    [JsonPropertyName("out_msgs")]
    public long OutMsgs { get; set; }

    [JsonPropertyName("in_bytes")]
    public long InBytes { get; set; }

    [JsonPropertyName("out_bytes")]
    public long OutBytes { get; set; }
}

/// <summary>Server shutdown notification.</summary>
public sealed class ShutdownEventMsg
{
    [JsonPropertyName("server")]
    public EventServerInfo Server { get; set; } = new();

    [JsonPropertyName("reason")]
    public string Reason { get; set; } = string.Empty;
}

/// <summary>Lame duck mode notification.</summary>
public sealed class LameDuckEventMsg
{
    [JsonPropertyName("server")]
    public EventServerInfo Server { get; set; } = new();
}

/// <summary>Auth error advisory.</summary>
public sealed class AuthErrorEventMsg
{
    public const string EventType = "io.nats.server.advisory.v1.client_auth";

    [JsonPropertyName("type")]
    public string Type { get; set; } = EventType;

    [JsonPropertyName("id")]
    public string Id { get; set; } = string.Empty;

    [JsonPropertyName("timestamp")]
    public DateTime Time { get; set; }

    [JsonPropertyName("server")]
    public EventServerInfo Server { get; set; } = new();

    [JsonPropertyName("client")]
    public EventClientInfo Client { get; set; } = new();

    [JsonPropertyName("reason")]
    public string Reason { get; set; } = string.Empty;
}

/// <summary>
/// OCSP peer rejection advisory.
/// Go reference: events.go:182-188 OCSPPeerRejectEventMsg.
/// </summary>
public sealed class OcspPeerRejectEventMsg
{
    public const string EventType = "io.nats.server.advisory.v1.ocsp_peer_reject";

    [JsonPropertyName("type")]
    public string Type { get; set; } = EventType;

    [JsonPropertyName("id")]
    public string Id { get; set; } = string.Empty;

    [JsonPropertyName("timestamp")]
    public DateTime Time { get; set; }

    [JsonPropertyName("kind")]
    public string Kind { get; set; } = "";

    [JsonPropertyName("server")]
    public EventServerInfo Server { get; set; } = new();

    [JsonPropertyName("reason")]
    public string Reason { get; set; } = string.Empty;
}

/// <summary>
/// Account numeric connections request.
/// Go reference: events.go:233-236 accNumConnsReq.
/// </summary>
public sealed class AccNumConnsReq
{
    [JsonPropertyName("server")]
    public EventServerInfo Server { get; set; } = new();

    [JsonPropertyName("acc")]
    public string Account { get; set; } = string.Empty;
}
