namespace Zcbot.WindowsNode;

internal sealed record EnrollOptions(Uri ServerUrl, string NodeName, string EnrollmentCode)
{
    internal static EnrollOptions Parse(string[] args)
    {
        var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        for (var index = 0; index < args.Length; index += 2)
        {
            if (index + 1 >= args.Length || !args[index].StartsWith("--", StringComparison.Ordinal))
            {
                throw Usage();
            }
            values[args[index][2..]] = args[index + 1];
        }

        if (!values.TryGetValue("server", out var server)
            || !values.TryGetValue("name", out var name)
            || !values.TryGetValue("code", out var code))
        {
            throw Usage();
        }

        var serverUrl = NodeUri.NormalizeServerUrl(server);
        name = name.Trim();
        code = code.Trim();
        if (name.Length is < 1 or > 100 || code.Length is < 16 or > 100)
        {
            throw new NodeConfigurationException("Node name or enrollment code has an invalid length.");
        }
        return new EnrollOptions(serverUrl, name, code);
    }

    private static NodeConfigurationException Usage() => new(
        "Usage: Zcbot.WindowsNode enroll --server http://host:8765 --name win-origin-01 --code ZCN-...");
}

internal static class NodeUri
{
    internal static Uri NormalizeServerUrl(string raw)
    {
        if (!Uri.TryCreate(raw.Trim(), UriKind.Absolute, out var uri)
            || (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)
            || !string.IsNullOrEmpty(uri.UserInfo)
            || !string.IsNullOrEmpty(uri.Query)
            || !string.IsNullOrEmpty(uri.Fragment))
        {
            throw new NodeConfigurationException("Server URL must be an absolute HTTP or HTTPS URL without credentials, query, or fragment.");
        }
        return new Uri(uri.GetLeftPart(UriPartial.Path).TrimEnd('/') + "/", UriKind.Absolute);
    }

    internal static Uri WebSocketEndpoint(Uri serverUrl)
    {
        var builder = new UriBuilder(new Uri(serverUrl, "v1/software-nodes/connect"))
        {
            Scheme = serverUrl.Scheme == Uri.UriSchemeHttps ? "wss" : "ws"
        };
        return builder.Uri;
    }
}
