using System.Globalization;
using System.Text.RegularExpressions;

namespace NATS.Server.Server;

/// <summary>
/// Misc utility helpers ported from Go's server/util.go.
/// </summary>
public static class ServerUtilities
{
    private static readonly Regex UrlAuthRegex = new(
        @"^(?<scheme>[a-zA-Z][a-zA-Z0-9+\-.]*://)(?<user>[^:@/]+):(?<pass>[^@/]+)@(?<rest>.+)$",
        RegexOptions.Compiled);

    /// <summary>
    /// Parse a host/port string with a default port fallback.
    /// Mirrors util.go parseHostPort behavior where 0/-1 port values fall back.
    /// </summary>
    public static (string Host, int Port) ParseHostPort(string hostPort, int defaultPort)
    {
        if (string.IsNullOrWhiteSpace(hostPort))
            throw new ArgumentException("no hostport specified", nameof(hostPort));

        var input = hostPort.Trim();

        if (input.StartsWith('['))
        {
            var endBracket = input.IndexOf(']');
            if (endBracket < 0)
                throw new FormatException($"Invalid host:port '{hostPort}'");

            var host = input[1..endBracket].Trim();
            if (endBracket + 1 >= input.Length || input[endBracket + 1] != ':')
                return (host, defaultPort);

            var portText = input[(endBracket + 2)..].Trim();
            if (!int.TryParse(portText, NumberStyles.Integer, CultureInfo.InvariantCulture, out var ipv6Port))
                throw new FormatException($"Invalid host:port '{hostPort}'");
            if (ipv6Port == 0 || ipv6Port == -1)
                ipv6Port = defaultPort;
            return (host, ipv6Port);
        }

        var colonIdx = input.LastIndexOf(':');
        if (colonIdx < 0)
            return (input, defaultPort);

        var parsedHost = input[..colonIdx].Trim();
        var parsedPortText = input[(colonIdx + 1)..].Trim();

        if (parsedPortText.Length == 0)
            return (parsedHost, defaultPort);

        if (!int.TryParse(parsedPortText, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedPort))
            throw new FormatException($"Invalid host:port '{hostPort}'");

        if (parsedPort == 0 || parsedPort == -1)
            parsedPort = defaultPort;

        return (parsedHost, parsedPort);
    }

    /// <summary>
    /// Redacts password in a single URL user-info section.
    /// </summary>
    public static string RedactUrlString(string url)
    {
        var match = UrlAuthRegex.Match(url);
        if (!match.Success)
            return url;

        return $"{match.Groups["scheme"].Value}{match.Groups["user"].Value}:xxxxx@{match.Groups["rest"].Value}";
    }

    /// <summary>
    /// Redacts URL credentials for a URL list.
    /// </summary>
    public static IReadOnlyList<string> RedactUrlList(IEnumerable<string> urls)
    {
        return urls.Select(RedactUrlString).ToArray();
    }
}
