// Copyright 2012-2025 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Adapted from server/const.go in the NATS server Go source.

using System.Reflection;

namespace ZB.MOM.NatsNet.Server;

/// <summary>
/// Server-wide constants and version information.
/// Mirrors server/const.go.
/// </summary>
public static class ServerConstants
{
    // Server version — mirrors VERSION in const.go.
    public const string Version = "2.14.0-dev";

    // Protocol version — mirrors PROTO in const.go.
    public const int Proto = 1;

    // Default port for client connections — mirrors DEFAULT_PORT.
    public const int DefaultPort = 4222;

    // Sentinel port value that triggers a random port selection — mirrors RANDOM_PORT.
    public const int RandomPort = -1;

    // Default bind address — mirrors DEFAULT_HOST.
    public const string DefaultHost = "0.0.0.0";

    // Maximum allowed control line size (4 KB) — mirrors MAX_CONTROL_LINE_SIZE.
    public const int MaxControlLineSize = 4096;

    // Maximum allowed payload size (1 MB) — mirrors MAX_PAYLOAD_SIZE.
    public const int MaxPayloadSize = 1024 * 1024;

    // Payload size above which the server warns — mirrors MAX_PAYLOAD_MAX_SIZE.
    public const int MaxPayloadMaxSize = 8 * 1024 * 1024;

    // Maximum outbound pending bytes per client (64 MB) — mirrors MAX_PENDING_SIZE.
    public const int MaxPendingSize = 64 * 1024 * 1024;

    // Default maximum connections allowed (64 K) — mirrors DEFAULT_MAX_CONNECTIONS.
    public const int DefaultMaxConnections = 64 * 1024;

    // TLS handshake timeout — mirrors TLS_TIMEOUT.
    public static readonly TimeSpan TlsTimeout = TimeSpan.FromSeconds(2);

    // Fallback delay before sending INFO when using TLSHandshakeFirst
    // — mirrors DEFAULT_TLS_HANDSHAKE_FIRST_FALLBACK_DELAY.
    public static readonly TimeSpan DefaultTlsHandshakeFirstFallbackDelay = TimeSpan.FromMilliseconds(50);

    // Auth timeout — mirrors AUTH_TIMEOUT.
    public static readonly TimeSpan AuthTimeout = TimeSpan.FromSeconds(2);

    // Default auth timeout as a double (seconds) — used by ServerOptions.AuthTimeout.
    public const double DefaultAuthTimeout = 2.0;

    // Maximum payload size alias used by config binding — mirrors MAX_PAYLOAD_SIZE.
    public const int MaxPayload = MaxPayloadSize;

    // How often pings are sent — mirrors DEFAULT_PING_INTERVAL.
    public static readonly TimeSpan DefaultPingInterval = TimeSpan.FromMinutes(2);

    // Maximum pings outstanding before disconnect — mirrors DEFAULT_PING_MAX_OUT.
    public const int DefaultPingMaxOut = 2;

    // CR LF end-of-line — mirrors CR_LF.
    public const string CrLf = "\r\n";

    // Length of CR_LF — mirrors LEN_CR_LF.
    public const int LenCrLf = 2;

    // Write/flush deadline — mirrors DEFAULT_FLUSH_DEADLINE.
    public static readonly TimeSpan DefaultFlushDeadline = TimeSpan.FromSeconds(10);

    // Default monitoring port — mirrors DEFAULT_HTTP_PORT.
    public const int DefaultHttpPort = 8222;

    // Default monitoring base path — mirrors DEFAULT_HTTP_BASE_PATH.
    public const string DefaultHttpBasePath = "/";

    // Minimum sleep on temporary accept errors — mirrors ACCEPT_MIN_SLEEP.
    public static readonly TimeSpan AcceptMinSleep = TimeSpan.FromMilliseconds(10);

    // Maximum sleep on temporary accept errors — mirrors ACCEPT_MAX_SLEEP.
    public static readonly TimeSpan AcceptMaxSleep = TimeSpan.FromSeconds(1);

    // Route solicitation interval — mirrors DEFAULT_ROUTE_CONNECT.
    public static readonly TimeSpan DefaultRouteConnect = TimeSpan.FromSeconds(1);

    // Maximum route solicitation interval — mirrors DEFAULT_ROUTE_CONNECT_MAX.
    public static readonly TimeSpan DefaultRouteConnectMax = TimeSpan.FromSeconds(30);

    // Route reconnect delay — mirrors DEFAULT_ROUTE_RECONNECT.
    public static readonly TimeSpan DefaultRouteReconnect = TimeSpan.FromSeconds(1);

    // Route dial timeout — mirrors DEFAULT_ROUTE_DIAL.
    public static readonly TimeSpan DefaultRouteDial = TimeSpan.FromSeconds(1);

    // Default route pool size — mirrors DEFAULT_ROUTE_POOL_SIZE.
    public const int DefaultRoutePoolSize = 3;

    // LeafNode reconnect interval — mirrors DEFAULT_LEAF_NODE_RECONNECT.
    public static readonly TimeSpan DefaultLeafNodeReconnect = TimeSpan.FromSeconds(1);

    // TLS timeout for leaf nodes — mirrors DEFAULT_LEAF_TLS_TIMEOUT.
    public static readonly TimeSpan DefaultLeafTlsTimeout = TimeSpan.FromSeconds(2);

    // Proto snippet size for parse error display — mirrors PROTO_SNIPPET_SIZE.
    public const int ProtoSnippetSize = 32;

    // Max control line snippet size for error display — mirrors MAX_CONTROL_LINE_SNIPPET_SIZE.
    public const int MaxControlLineSnippetSize = 128;

    // Maximum MSG proto argument count — mirrors MAX_MSG_ARGS.
    public const int MaxMsgArgs = 4;

    // Maximum RMSG proto argument count — mirrors MAX_RMSG_ARGS.
    public const int MaxRMsgArgs = 6;

    // Maximum HMSG proto argument count — mirrors MAX_HMSG_ARGS.
    public const int MaxHMsgArgs = 7;

    // Maximum PUB proto argument count — mirrors MAX_PUB_ARGS.
    public const int MaxPubArgs = 3;

    // Maximum HPUB proto argument count — mirrors MAX_HPUB_ARGS.
    public const int MaxHPubArgs = 4;

    // Maximum RS+/LS+ proto argument count — mirrors MAX_RSUB_ARGS.
    public const int MaxRSubArgs = 6;

    // Maximum closed connections retained — mirrors DEFAULT_MAX_CLOSED_CLIENTS.
    public const int DefaultMaxClosedClients = 10000;

    // Lame duck spread duration — mirrors DEFAULT_LAME_DUCK_DURATION.
    public static readonly TimeSpan DefaultLameDuckDuration = TimeSpan.FromMinutes(2);

    // Lame duck grace period — mirrors DEFAULT_LAME_DUCK_GRACE_PERIOD.
    public static readonly TimeSpan DefaultLameDuckGracePeriod = TimeSpan.FromSeconds(10);

    // Leaf node INFO wait — mirrors DEFAULT_LEAFNODE_INFO_WAIT.
    public static readonly TimeSpan DefaultLeafNodeInfoWait = TimeSpan.FromSeconds(1);

    // Default leaf node port — mirrors DEFAULT_LEAFNODE_PORT.
    public const int DefaultLeafNodePort = 7422;

    // Connect error report threshold — mirrors DEFAULT_CONNECT_ERROR_REPORTS.
    public const int DefaultConnectErrorReports = 3600;

    // Reconnect error report threshold — mirrors DEFAULT_RECONNECT_ERROR_REPORTS.
    public const int DefaultReconnectErrorReports = 1;

    // RTT measurement interval — mirrors DEFAULT_RTT_MEASUREMENT_INTERVAL.
    public static readonly TimeSpan DefaultRttMeasurementInterval = TimeSpan.FromHours(1);

    // Default allowed response max messages — mirrors DEFAULT_ALLOW_RESPONSE_MAX_MSGS.
    public const int DefaultAllowResponseMaxMsgs = 1;

    // Default allowed response expiration — mirrors DEFAULT_ALLOW_RESPONSE_EXPIRATION.
    public static readonly TimeSpan DefaultAllowResponseExpiration = TimeSpan.FromMinutes(2);

    // Default service export response threshold — mirrors DEFAULT_SERVICE_EXPORT_RESPONSE_THRESHOLD.
    public static readonly TimeSpan DefaultServiceExportResponseThreshold = TimeSpan.FromMinutes(2);

    // Default service latency sampling rate — mirrors DEFAULT_SERVICE_LATENCY_SAMPLING.
    public const int DefaultServiceLatencySampling = 100;

    // Default system account name — mirrors DEFAULT_SYSTEM_ACCOUNT.
    public const string DefaultSystemAccount = "$SYS";

    // Default global account name — mirrors DEFAULT_GLOBAL_ACCOUNT.
    public const string DefaultGlobalAccount = "$G";

    // Default account fetch timeout — mirrors DEFAULT_ACCOUNT_FETCH_TIMEOUT.
    public static readonly TimeSpan DefaultAccountFetchTimeout = TimeSpan.FromMilliseconds(1900);

    // VCS commit hash embedded at build time, shortened to 7 chars — mirrors gitCommit.
    // Populated from AssemblyInformationalVersion metadata if available.
    public static readonly string GitCommit;

    static ServerConstants()
    {
        // Mirror const.go init(): extract VCS revision from build info.
        // In .NET we read the AssemblyInformationalVersion attribute which
        // is typically set to the semantic version + commit hash by dotnet publish.
        var infoVersion = typeof(ServerConstants).Assembly
            .GetCustomAttribute<AssemblyInformationalVersionAttribute>()
            ?.InformationalVersion;

        if (infoVersion != null)
        {
            // Convention: "1.2.3+abcdefg" or "1.2.3-dev+abcdefg"
            var plusIdx = infoVersion.IndexOf('+');
            if (plusIdx >= 0)
            {
                var rev = infoVersion[(plusIdx + 1)..];
                GitCommit = FormatRevision(rev);
                return;
            }
        }

        GitCommit = string.Empty;
    }

    /// <summary>
    /// Compatibility init hook for PortTracker parity with Go <c>init()</c>.
    /// Safe and idempotent.
    /// </summary>
    public static void Init()
    {
        _ = GitCommit;
    }

    /// <summary>
    /// Truncates a VCS revision string to 7 characters for display.
    /// Mirrors <c>formatRevision</c> in const.go.
    /// </summary>
    public static string FormatRevision(string revision) =>
        revision.Length >= 7 ? revision[..7] : revision;
}

/// <summary>
/// Server control commands — mirrors the <c>Command</c> type in const.go.
/// </summary>
public enum ServerCommand
{
    Stop,
    Quit,
    Reopen,
    Reload,
    Term,
    LameDuckMode,
}
