using System.Text.Json.Serialization;

namespace NATS.Server.Monitoring;

/// <summary>
/// Server general information. Corresponds to Go server/monitor.go Varz struct.
/// </summary>
public sealed class Varz
{
    // Identity
    [JsonPropertyName("server_id")]
    public string Id { get; set; } = "";

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

    [JsonPropertyName("version")]
    public string Version { get; set; } = "";

    [JsonPropertyName("proto")]
    public int Proto { get; set; }

    [JsonPropertyName("git_commit")]
    public string GitCommit { get; set; } = "";

    [JsonPropertyName("go")]
    public string GoVersion { get; set; } = "";

    [JsonPropertyName("host")]
    public string Host { get; set; } = "";

    [JsonPropertyName("port")]
    public int Port { get; set; }

    // Network
    [JsonPropertyName("ip")]
    public string Ip { get; set; } = "";

    [JsonPropertyName("connect_urls")]
    public string[] ConnectUrls { get; set; } = [];

    [JsonPropertyName("ws_connect_urls")]
    public string[] WsConnectUrls { get; set; } = [];

    [JsonPropertyName("http_host")]
    public string HttpHost { get; set; } = "";

    [JsonPropertyName("http_port")]
    public int HttpPort { get; set; }

    [JsonPropertyName("http_base_path")]
    public string HttpBasePath { get; set; } = "";

    [JsonPropertyName("https_port")]
    public int HttpsPort { get; set; }

    // Security
    [JsonPropertyName("auth_required")]
    public bool AuthRequired { get; set; }

    [JsonPropertyName("tls_required")]
    public bool TlsRequired { get; set; }

    [JsonPropertyName("tls_verify")]
    public bool TlsVerify { get; set; }

    [JsonPropertyName("tls_ocsp_peer_verify")]
    public bool TlsOcspPeerVerify { get; set; }

    [JsonPropertyName("auth_timeout")]
    public double AuthTimeout { get; set; }

    [JsonPropertyName("tls_timeout")]
    public double TlsTimeout { get; set; }

    // Limits
    [JsonPropertyName("max_connections")]
    public int MaxConnections { get; set; }

    [JsonPropertyName("max_subscriptions")]
    public int MaxSubscriptions { get; set; }

    [JsonPropertyName("max_payload")]
    public int MaxPayload { get; set; }

    [JsonPropertyName("max_pending")]
    public long MaxPending { get; set; }

    [JsonPropertyName("max_control_line")]
    public int MaxControlLine { get; set; }

    [JsonPropertyName("ping_max")]
    public int MaxPingsOut { get; set; }

    // Timing
    [JsonPropertyName("ping_interval")]
    public long PingInterval { get; set; }

    [JsonPropertyName("write_deadline")]
    public long WriteDeadline { get; set; }

    [JsonPropertyName("start")]
    public DateTime Start { get; set; }

    [JsonPropertyName("now")]
    public DateTime Now { get; set; }

    [JsonPropertyName("uptime")]
    public string Uptime { get; set; } = "";

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

    [JsonPropertyName("cpu")]
    public double Cpu { get; set; }

    [JsonPropertyName("cores")]
    public int Cores { get; set; }

    [JsonPropertyName("gomaxprocs")]
    public int MaxProcs { get; set; }

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

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

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

    [JsonPropertyName("remotes")]
    public int Remotes { get; set; }

    [JsonPropertyName("leafnodes")]
    public int Leafnodes { get; set; }

    // Messages
    [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; }

    // Health
    [JsonPropertyName("slow_consumers")]
    public long SlowConsumers { get; set; }

    [JsonPropertyName("slow_consumer_stats")]
    public SlowConsumersStats SlowConsumerStats { get; set; } = new();

    [JsonPropertyName("stale_connections")]
    public long StaleConnections { get; set; }

    [JsonPropertyName("stale_connection_stats")]
    public StaleConnectionStats StaleConnectionStatsDetail { get; set; } = new();

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

    // Config
    [JsonPropertyName("config_load_time")]
    public DateTime ConfigLoadTime { get; set; }

    [JsonPropertyName("tags")]
    public string[] Tags { get; set; } = [];

    [JsonPropertyName("system_account")]
    public string SystemAccount { get; set; } = "";

    [JsonPropertyName("pinned_account_fails")]
    public ulong PinnedAccountFail { get; set; }

    [JsonPropertyName("tls_cert_not_after")]
    public DateTime TlsCertNotAfter { get; set; }

    // HTTP
    [JsonPropertyName("http_req_stats")]
    public Dictionary<string, ulong> HttpReqStats { get; set; } = new();

    // Subsystems
    [JsonPropertyName("cluster")]
    public ClusterOptsVarz Cluster { get; set; } = new();

    [JsonPropertyName("gateway")]
    public GatewayOptsVarz Gateway { get; set; } = new();

    [JsonPropertyName("leaf")]
    public LeafNodeOptsVarz Leaf { get; set; } = new();

    [JsonPropertyName("mqtt")]
    public MqttOptsVarz Mqtt { get; set; } = new();

    [JsonPropertyName("websocket")]
    public WebsocketOptsVarz Websocket { get; set; } = new();

    [JsonPropertyName("jetstream")]
    public JetStreamVarz JetStream { get; set; } = new();
}

/// <summary>
/// Statistics about slow consumers by connection type.
/// Corresponds to Go server/monitor.go SlowConsumersStats struct.
/// </summary>
public sealed class SlowConsumersStats
{
    [JsonPropertyName("clients")]
    public ulong Clients { get; set; }

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

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

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

/// <summary>
/// Statistics about stale connections by connection type.
/// Corresponds to Go server/monitor.go StaleConnectionStats struct.
/// </summary>
public sealed class StaleConnectionStats
{
    [JsonPropertyName("clients")]
    public ulong Clients { get; set; }

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

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

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

/// <summary>
/// Cluster configuration monitoring information.
/// Corresponds to Go server/monitor.go ClusterOptsVarz struct.
/// </summary>
public sealed class ClusterOptsVarz
{
    [JsonPropertyName("name")]
    public string Name { get; set; } = "";

    [JsonPropertyName("addr")]
    public string Host { get; set; } = "";

    [JsonPropertyName("cluster_port")]
    public int Port { get; set; }

    [JsonPropertyName("auth_timeout")]
    public double AuthTimeout { get; set; }

    [JsonPropertyName("tls_timeout")]
    public double TlsTimeout { get; set; }

    [JsonPropertyName("tls_required")]
    public bool TlsRequired { get; set; }

    [JsonPropertyName("tls_verify")]
    public bool TlsVerify { get; set; }

    [JsonPropertyName("pool_size")]
    public int PoolSize { get; set; }

    [JsonPropertyName("urls")]
    public string[] Urls { get; set; } = [];
}

/// <summary>
/// Gateway configuration monitoring information.
/// Corresponds to Go server/monitor.go GatewayOptsVarz struct.
/// </summary>
public sealed class GatewayOptsVarz
{
    [JsonPropertyName("name")]
    public string Name { get; set; } = "";

    [JsonPropertyName("host")]
    public string Host { get; set; } = "";

    [JsonPropertyName("port")]
    public int Port { get; set; }

    [JsonPropertyName("auth_timeout")]
    public double AuthTimeout { get; set; }

    [JsonPropertyName("tls_timeout")]
    public double TlsTimeout { get; set; }

    [JsonPropertyName("tls_required")]
    public bool TlsRequired { get; set; }

    [JsonPropertyName("tls_verify")]
    public bool TlsVerify { get; set; }

    [JsonPropertyName("advertise")]
    public string Advertise { get; set; } = "";

    [JsonPropertyName("connect_retries")]
    public int ConnectRetries { get; set; }

    [JsonPropertyName("reject_unknown")]
    public bool RejectUnknown { get; set; }
}

/// <summary>
/// Leaf node configuration monitoring information.
/// Corresponds to Go server/monitor.go LeafNodeOptsVarz struct.
/// </summary>
public sealed class LeafNodeOptsVarz
{
    [JsonPropertyName("host")]
    public string Host { get; set; } = "";

    [JsonPropertyName("port")]
    public int Port { get; set; }

    [JsonPropertyName("auth_timeout")]
    public double AuthTimeout { get; set; }

    [JsonPropertyName("tls_timeout")]
    public double TlsTimeout { get; set; }

    [JsonPropertyName("tls_required")]
    public bool TlsRequired { get; set; }

    [JsonPropertyName("tls_verify")]
    public bool TlsVerify { get; set; }

    [JsonPropertyName("tls_ocsp_peer_verify")]
    public bool TlsOcspPeerVerify { get; set; }
}

/// <summary>
/// MQTT configuration monitoring information.
/// Corresponds to Go server/monitor.go MQTTOptsVarz struct.
/// </summary>
public sealed class MqttOptsVarz
{
    [JsonPropertyName("host")]
    public string Host { get; set; } = "";

    [JsonPropertyName("port")]
    public int Port { get; set; }

    [JsonPropertyName("no_auth_user")]
    public string NoAuthUser { get; set; } = "";

    [JsonPropertyName("auth_timeout")]
    public double AuthTimeout { get; set; }

    [JsonPropertyName("tls_map")]
    public bool TlsMap { get; set; }

    [JsonPropertyName("tls_timeout")]
    public double TlsTimeout { get; set; }

    [JsonPropertyName("tls_pinned_certs")]
    public string[] TlsPinnedCerts { get; set; } = [];

    [JsonPropertyName("js_domain")]
    public string JsDomain { get; set; } = "";

    [JsonPropertyName("ack_wait")]
    public long AckWait { get; set; }

    [JsonPropertyName("max_ack_pending")]
    public ushort MaxAckPending { get; set; }
}

/// <summary>
/// Websocket configuration monitoring information.
/// Corresponds to Go server/monitor.go WebsocketOptsVarz struct.
/// </summary>
public sealed class WebsocketOptsVarz
{
    [JsonPropertyName("host")]
    public string Host { get; set; } = "";

    [JsonPropertyName("port")]
    public int Port { get; set; }

    [JsonPropertyName("tls_timeout")]
    public double TlsTimeout { get; set; }
}

/// <summary>
/// JetStream runtime information.
/// Corresponds to Go server/monitor.go JetStreamVarz struct.
/// </summary>
public sealed class JetStreamVarz
{
    [JsonPropertyName("config")]
    public JetStreamConfig Config { get; set; } = new();

    [JsonPropertyName("stats")]
    public JetStreamStats Stats { get; set; } = new();
}

/// <summary>
/// JetStream configuration.
/// Corresponds to Go server/jetstream.go JetStreamConfig struct.
/// </summary>
public sealed class JetStreamConfig
{
    [JsonPropertyName("max_memory")]
    public long MaxMemory { get; set; }

    [JsonPropertyName("max_storage")]
    public long MaxStorage { get; set; }

    [JsonPropertyName("store_dir")]
    public string StoreDir { get; set; } = "";
}

/// <summary>
/// JetStream statistics.
/// Corresponds to Go server/jetstream.go JetStreamStats struct.
/// </summary>
public sealed class JetStreamStats
{
    [JsonPropertyName("memory")]
    public ulong Memory { get; set; }

    [JsonPropertyName("storage")]
    public ulong Storage { get; set; }

    [JsonPropertyName("accounts")]
    public int Accounts { get; set; }

    [JsonPropertyName("ha_assets")]
    public int HaAssets { get; set; }

    [JsonPropertyName("streams")]
    public int Streams { get; set; }

    [JsonPropertyName("consumers")]
    public int Consumers { get; set; }

    [JsonPropertyName("api")]
    public JetStreamApiStats Api { get; set; } = new();
}

/// <summary>
/// JetStream API statistics.
/// Corresponds to Go server/jetstream.go JetStreamAPIStats struct.
/// </summary>
public sealed class JetStreamApiStats
{
    [JsonPropertyName("total")]
    public ulong Total { get; set; }

    [JsonPropertyName("errors")]
    public ulong Errors { get; set; }
}
