using System.Security.Authentication;
using NATS.Server.Auth;
using NATS.Server.Configuration;
using NATS.Server.Tls;

namespace NATS.Server;

public sealed class NatsOptions
{
    public string Host { get; set; } = "0.0.0.0";
    public int Port { get; set; } = 4222;
    public string? ServerName { get; set; }
    public int MaxPayload { get; set; } = 1024 * 1024;
    public int MaxControlLine { get; set; } = 4096;
    public int MaxConnections { get; set; } = 65536;
    public long MaxPending { get; set; } = 64 * 1024 * 1024; // 64MB, matching Go MAX_PENDING_SIZE
    public TimeSpan WriteDeadline { get; set; } = TimeSpan.FromSeconds(10);
    public TimeSpan PingInterval { get; set; } = TimeSpan.FromMinutes(2);
    public int MaxPingsOut { get; set; } = 2;

    // Subscription limits
    public int MaxSubs { get; set; }             // 0 = unlimited (per-connection)
    public int MaxSubTokens { get; set; }        // 0 = unlimited

    // Server tags (exposed via /varz)
    public Dictionary<string, string>? Tags { get; set; }

    // Account configuration
    public Dictionary<string, AccountConfig>? Accounts { get; set; }

    // Simple auth (single user)
    public string? Username { get; set; }
    public string? Password { get; set; }
    public string? Authorization { get; set; }

    // Multiple users/nkeys
    public IReadOnlyList<User>? Users { get; set; }
    public IReadOnlyList<NKeyUser>? NKeys { get; set; }

    // Default/fallback
    public string? NoAuthUser { get; set; }

    // Auth extensions
    public Auth.ExternalAuthOptions? ExternalAuth { get; set; }
    public Auth.ProxyAuthOptions? ProxyAuth { get; set; }

    // Auth timing
    public TimeSpan AuthTimeout { get; set; } = TimeSpan.FromSeconds(2);

    // Monitoring (0 = disabled; standard port is 8222)
    public int MonitorPort { get; set; }
    public string MonitorHost { get; set; } = "0.0.0.0";
    public string? MonitorBasePath { get; set; }
    // 0 = disabled
    public int MonitorHttpsPort { get; set; }

    // Lifecycle / lame-duck mode
    public TimeSpan LameDuckDuration { get; set; } = TimeSpan.FromMinutes(2);
    public TimeSpan LameDuckGracePeriod { get; set; } = TimeSpan.FromSeconds(10);

    // File paths
    public string? PidFile { get; set; }
    public string? PortsFileDir { get; set; }
    public string? ConfigFile { get; set; }

    // Logging
    public string? LogFile { get; set; }
    public long LogSizeLimit { get; set; }
    public int LogMaxFiles { get; set; }
    public bool Debug { get; set; }
    public bool Trace { get; set; }
    public bool Logtime { get; set; } = true;
    public bool LogtimeUTC { get; set; }
    public bool Syslog { get; set; }
    public string? RemoteSyslog { get; set; }

    // Profiling (0 = disabled)
    public int ProfPort { get; set; }

    // Extended options for Go parity
    public string? ClientAdvertise { get; set; }
    public bool TraceVerbose { get; set; }
    public int MaxTracedMsgLen { get; set; }
    public bool DisableSublistCache { get; set; }
    public int ConnectErrorReports { get; set; } = 3600;
    public int ReconnectErrorReports { get; set; } = 1;
    public bool NoHeaderSupport { get; set; }
    public int MaxClosedClients { get; set; } = 10_000;
    public bool NoSystemAccount { get; set; }
    public string? SystemAccount { get; set; }

    // Tracks which fields were set via CLI flags (for reload precedence)
    public HashSet<string> InCmdLine { get; } = [];

    // TLS
    public string? TlsCert { get; set; }
    public string? TlsKey { get; set; }
    public string? TlsCaCert { get; set; }
    public bool TlsVerify { get; set; }
    public bool TlsMap { get; set; }
    public TimeSpan TlsTimeout { get; set; } = TimeSpan.FromSeconds(2);
    public bool TlsHandshakeFirst { get; set; }
    public TimeSpan TlsHandshakeFirstFallback { get; set; } = TimeSpan.FromMilliseconds(50);
    public bool AllowNonTls { get; set; }
    public long TlsRateLimit { get; set; }
    public HashSet<string>? TlsPinnedCerts { get; set; }
    public SslProtocols TlsMinVersion { get; set; } = SslProtocols.Tls12;

    // OCSP stapling and peer verification
    public OcspConfig? OcspConfig { get; set; }
    public bool OcspPeerVerify { get; set; }

    // JWT / Operator mode
    public string[]? TrustedKeys { get; set; }
    public Auth.Jwt.IAccountResolver? AccountResolver { get; set; }

    // Per-subsystem log level overrides (namespace -> level)
    public Dictionary<string, string>? LogOverrides { get; set; }

    // Subject mapping / transforms (source pattern -> destination template)
    public Dictionary<string, string>? SubjectMappings { get; set; }

    // MQTT configuration (parsed from config, no listener yet)
    public MqttOptions? Mqtt { get; set; }

    // Cluster and JetStream settings
    public ClusterOptions? Cluster { get; set; }
    public GatewayOptions? Gateway { get; set; }
    public LeafNodeOptions? LeafNode { get; set; }
    public JetStreamOptions? JetStream { get; set; }

    public bool HasTls => TlsCert != null && TlsKey != null;

    // WebSocket
    public WebSocketOptions WebSocket { get; set; } = new();
}

public sealed class WebSocketOptions
{
    public string Host { get; set; } = "0.0.0.0";
    public int Port { get; set; } = -1;
    public string? Advertise { get; set; }
    public string? NoAuthUser { get; set; }
    public string? JwtCookie { get; set; }
    public string? UsernameCookie { get; set; }
    public string? PasswordCookie { get; set; }
    public string? TokenCookie { get; set; }
    public string? Username { get; set; }
    public string? Password { get; set; }
    public string? Token { get; set; }
    public TimeSpan AuthTimeout { get; set; } = TimeSpan.FromSeconds(2);
    public bool NoTls { get; set; }
    public string? TlsCert { get; set; }
    public string? TlsKey { get; set; }
    public bool SameOrigin { get; set; }
    public List<string>? AllowedOrigins { get; set; }
    public bool Compression { get; set; }
    public TimeSpan HandshakeTimeout { get; set; } = TimeSpan.FromSeconds(2);
    public TimeSpan? PingInterval { get; set; }
    public Dictionary<string, string>? Headers { get; set; }
}
