using System.Text.Json.Serialization;

namespace NATS.Server.Protocol;

public static class NatsProtocol
{
    public const int MaxControlLineSize = 4096;
    public const int MaxPayloadSize = 1024 * 1024; // 1MB
    public const long MaxPendingSize = 64 * 1024 * 1024; // 64MB default max pending
    public const int DefaultPort = 4222;
    public const string Version = "0.1.0";
    public const int ProtoVersion = 1;

    // Pre-encoded protocol fragments
    public static readonly byte[] CrLf = "\r\n"u8.ToArray();
    public static readonly byte[] PingBytes = "PING\r\n"u8.ToArray();
    public static readonly byte[] PongBytes = "PONG\r\n"u8.ToArray();
    public static readonly byte[] OkBytes = "+OK\r\n"u8.ToArray();
    public static readonly byte[] InfoPrefix = "INFO "u8.ToArray();
    public static readonly byte[] MsgPrefix = "MSG "u8.ToArray();
    public static readonly byte[] HmsgPrefix = "HMSG "u8.ToArray();
    public static readonly byte[] ErrPrefix = "-ERR "u8.ToArray();

    // Standard error messages (matching Go server)
    public const string ErrMaxConnectionsExceeded = "maximum connections exceeded";
    public const string ErrStaleConnection = "Stale Connection";
    public const string ErrMaxPayloadViolation = "Maximum Payload Violation";
    public const string ErrInvalidPublishSubject = "Invalid Publish Subject";
    public const string ErrInvalidSubject = "Invalid Subject";
    public const string ErrAuthorizationViolation = "Authorization Violation";
    public const string ErrAuthTimeout = "Authentication Timeout";
    public const string ErrPermissionsPublish = "Permissions Violation for Publish";
    public const string ErrPermissionsSubscribe = "Permissions Violation for Subscription";
    public const string ErrSlowConsumer = "Slow Consumer";
    public const string ErrNoRespondersRequiresHeaders = "No Responders Requires Headers Support";
    public const string ErrMaxSubscriptionsExceeded = "Maximum Subscriptions Exceeded";
}

public sealed class ServerInfo
{
    [JsonPropertyName("server_id")]
    public required string ServerId { get; set; }

    [JsonPropertyName("server_name")]
    public required string ServerName { get; set; }

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

    [JsonPropertyName("proto")]
    public int Proto { get; set; } = NatsProtocol.ProtoVersion;

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

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

    [JsonPropertyName("headers")]
    public bool Headers { get; set; } = true;

    [JsonPropertyName("max_payload")]
    public int MaxPayload { get; set; } = NatsProtocol.MaxPayloadSize;

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

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

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

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

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

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

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

public sealed class ClientOptions
{
    [JsonPropertyName("verbose")]
    public bool Verbose { get; set; }

    [JsonPropertyName("pedantic")]
    public bool Pedantic { get; set; }

    [JsonPropertyName("echo")]
    public bool Echo { get; set; } = true;

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

    [JsonPropertyName("lang")]
    public string? Lang { get; set; }

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

    [JsonPropertyName("protocol")]
    public int Protocol { get; set; }

    [JsonPropertyName("headers")]
    public bool Headers { get; set; }

    [JsonPropertyName("no_responders")]
    public bool NoResponders { get; set; }

    [JsonPropertyName("user")]
    public string? Username { get; set; }

    [JsonPropertyName("pass")]
    public string? Password { get; set; }

    [JsonPropertyName("auth_token")]
    public string? Token { get; set; }

    [JsonPropertyName("nkey")]
    public string? Nkey { get; set; }

    [JsonPropertyName("sig")]
    public string? Sig { get; set; }

    [JsonPropertyName("jwt")]
    public string? JWT { get; set; }
}
