using System.Diagnostics;
using System.Text.Json;

namespace Dada.Supervisor;

internal static class AiGatewayProbe
{
    internal static async Task<int> RunAsync(ICredentialStore credentials, CancellationToken cancellationToken = default)
    {
        var node = Path.Combine(AppContext.BaseDirectory, "runtime", "node.exe");
        var worker = Path.Combine(AppContext.BaseDirectory, "server", "worker.mjs");
        if (!File.Exists(node) || !File.Exists(worker)) return WriteFailure("ai_probe_runtime_missing", 0);
        var startInfo = new ProcessStartInfo(node) { WorkingDirectory = AppContext.BaseDirectory };
        startInfo.Environment["DADA_SQLITE_NATIVE_BINDING"] = Path.Combine(AppContext.BaseDirectory, "server", "native", "better_sqlite3.node");
        startInfo.ArgumentList.Add(worker);
        startInfo.ArgumentList.Add("--dada-ai-probe");
        startInfo.ArgumentList.Add("--dada-credential-stdin");
        var result = await CredentialProcessLauncher.RunToCompletionAsync(startInfo, ChildRole.Worker, credentials, cancellationToken);
        if (result.SensitiveOutputDetected || result.StandardError.Length > 0 || !TryValidateOutput(result.StandardOutput, out var sanitized))
        {
            return WriteFailure("ai_probe_runtime_failed", 0);
        }
        Console.WriteLine(sanitized);
        return result.ExitCode;
    }

    internal static bool TryValidateOutput(string output, out string sanitized)
    {
        sanitized = string.Empty;
        try
        {
            using var document = JsonDocument.Parse(output);
            var root = document.RootElement;
            if (root.ValueKind != JsonValueKind.Object) return false;
            var allowed = new HashSet<string>(StringComparer.Ordinal)
            {
                "code", "error_category", "mime_type", "pixel_height", "pixel_width", "real_calls", "success",
            };
            if (root.EnumerateObject().Any(property => !allowed.Contains(property.Name))) return false;
            if (!root.TryGetProperty("success", out var success) || success.ValueKind is not (JsonValueKind.True or JsonValueKind.False)) return false;
            if (!root.TryGetProperty("real_calls", out var realCalls) || realCalls.ValueKind != JsonValueKind.Number || !realCalls.TryGetInt32(out var count) || count is < 0 or > 1) return false;
            var passed = success.GetBoolean();
            var code = root.GetProperty("code").GetString();
            if (passed)
            {
                if (code != "ai_probe_passed" || count != 1) return false;
                var mime = root.GetProperty("mime_type").GetString();
                if (mime is not ("image/jpeg" or "image/png" or "image/webp")) return false;
                if (!PositiveDimension(root, "pixel_width") || !PositiveDimension(root, "pixel_height")) return false;
            }
            else
            {
                if (code != "ai_probe_failed" || !root.TryGetProperty("error_category", out var category)
                    || category.ValueKind != JsonValueKind.String || (category.GetString()?.Length ?? 0) is < 1 or > 64) return false;
            }
            sanitized = JsonSerializer.Serialize(root);
            return true;
        }
        catch (Exception exception) when (exception is JsonException or InvalidOperationException or KeyNotFoundException)
        {
            return false;
        }
    }

    private static bool PositiveDimension(JsonElement root, string name) =>
        root.TryGetProperty(name, out var value) && value.ValueKind == JsonValueKind.Number
        && value.TryGetInt32(out var dimension) && dimension is > 0 and <= 4096;

    private static int WriteFailure(string code, int realCalls)
    {
        Console.WriteLine(JsonSerializer.Serialize(new { code, real_calls = realCalls, success = false }));
        return 2;
    }
}
