import { spawn } from "node:child_process";
import { describeComputeTarget } from "./compute.js";
import { codexOAuthModels, hasCodexCliOAuth, resolveCodexExecutable } from "./codex.js";
import { GeminiClient, readGeminiApiKey } from "./gemini.js";
import { GeminiWrapperClient, ensureGeminiWebApiInstalled, geminiWebApiInstallCommand, geminiWrapperRequiresApiKey, isGeminiBrowserCookieImportInstalled, isGeminiWebApiInstalled, readGeminiWrapperApiKey, readGeminiWrapperBaseUrl, readGeminiWrapperCookiesJson, readGeminiWrapperMode, readGeminiWrapperPythonCommand, readGeminiWrapperSecure1psid } from "./geminiWrapper.js";
import { NvidiaClient, readNvidiaApiKey } from "./nvidia.js";
import { OllamaClient } from "./ollama.js";
import { OpenRouterClient, readOpenRouterApiKey } from "./openrouter.js";
export async function runDoctor(provider, ollamaUrl, model, options = {}) {
    const results = [];
    results.push(await checkCommand("node", ["--version"]));
    results.push(await checkCommand("git", ["--version"]));
    if (provider === "gemini") {
        results.push(...(await checkGemini(model)));
        return results;
    }
    if (provider === "gemini-wrapper") {
        results.push(...(await checkGeminiWrapper(model, options)));
        return results;
    }
    if (provider === "codex") {
        results.push(...(await checkCodex(model)));
        return results;
    }
    if (provider === "openrouter") {
        results.push(...(await checkOpenRouter(model)));
        return results;
    }
    if (provider === "nvidia") {
        results.push(...(await checkNvidia(model)));
        return results;
    }
    const computeTarget = describeComputeTarget(ollamaUrl);
    if (computeTarget.kind === "local") {
        results.push(await checkCommand("ollama", ["--version"], "ollama-cli", "Install Ollama and ensure the ollama CLI is available on PATH."));
    }
    else {
        results.push({
            name: "ollama-cli",
            ok: true,
            details: `not required locally while using ${computeTarget.label}`
        });
    }
    const ollama = new OllamaClient(ollamaUrl);
    try {
        const models = await ollama.listModels();
        results.push({
            name: "ollama",
            ok: true,
            details: models.length > 0 ? `available models: ${models.join(", ")}` : "server reachable, no models pulled"
        });
        if (model) {
            results.push({
                name: "ollama-model",
                ok: models.includes(model),
                details: models.includes(model) ? `${model} is available` : `${model} is missing. Run: ollama pull ${model}`
            });
        }
    }
    catch (error) {
        results.push({
            name: "ollama",
            ok: false,
            details: error instanceof Error ? error.message : String(error)
        });
    }
    return results;
}
async function checkOpenRouter(model) {
    const results = [
        {
            name: "openrouter-key",
            ok: Boolean(readOpenRouterApiKey()),
            details: readOpenRouterApiKey() ? "OPENROUTER_API_KEY is configured" : "missing. Add OPENROUTER_API_KEY to PatchPilot config"
        }
    ];
    if (!readOpenRouterApiKey()) {
        return results;
    }
    try {
        const models = await new OpenRouterClient().listModels();
        results.push({
            name: "openrouter",
            ok: true,
            details: models.length > 0 ? `available models: ${models.slice(0, 12).join(", ")}` : "API reachable, no models listed"
        });
        if (model) {
            results.push({
                name: "openrouter-model",
                ok: models.includes(model),
                details: models.includes(model) ? `${model} is available` : `${model} is not listed by OpenRouter models API`
            });
        }
    }
    catch (error) {
        results.push({
            name: "openrouter",
            ok: false,
            details: error instanceof Error ? error.message : String(error)
        });
    }
    return results;
}
async function checkNvidia(model) {
    const results = [
        {
            name: "nvidia-key",
            ok: Boolean(readNvidiaApiKey()),
            details: readNvidiaApiKey() ? "NVIDIA_API_KEY is configured" : "missing. Add NVIDIA_API_KEY to PatchPilot config"
        }
    ];
    if (!readNvidiaApiKey()) {
        return results;
    }
    try {
        const models = await new NvidiaClient().listModels();
        results.push({
            name: "nvidia",
            ok: true,
            details: models.length > 0 ? `available models: ${models.slice(0, 12).join(", ")}` : "API reachable, no models listed"
        });
        if (model) {
            results.push({
                name: "nvidia-model",
                ok: models.includes(model),
                details: models.includes(model) ? `${model} is available` : `${model} is not listed by NVIDIA models API`
            });
        }
    }
    catch (error) {
        results.push({
            name: "nvidia",
            ok: false,
            details: error instanceof Error ? error.message : String(error)
        });
    }
    return results;
}
async function checkCodex(model) {
    const cli = await checkCommand(resolveCodexExecutable(), ["--version"], "codex-cli", "Install Codex CLI, then run codex login.");
    const hasOAuth = hasCodexCliOAuth();
    const results = [
        cli,
        {
            name: "codex-auth",
            ok: hasOAuth,
            details: hasOAuth ? "Codex CLI OAuth tokens are present" : "missing. Run: codex login"
        }
    ];
    if (!cli.ok || !hasOAuth) {
        return results;
    }
    results.push({
        name: "codex",
        ok: true,
        details: `OAuth backend ready. Models: ${codexOAuthModels.join(", ")}`
    });
    if (model) {
        results.push({
            name: "codex-model",
            ok: codexOAuthModels.includes(model),
            details: codexOAuthModels.includes(model) ? `${model} is available` : `${model} is not in the Codex OAuth model list`
        });
    }
    return results;
}
async function checkGemini(model) {
    const results = [
        {
            name: "gemini-key",
            ok: Boolean(readGeminiApiKey()),
            details: readGeminiApiKey() ? "GEMINI_API_KEY is configured" : "missing. Add GEMINI_API_KEY to .env"
        }
    ];
    if (!readGeminiApiKey()) {
        return results;
    }
    const gemini = new GeminiClient();
    try {
        const models = await gemini.listModels();
        results.push({
            name: "gemini",
            ok: true,
            details: models.length > 0 ? `available models: ${models.slice(0, 12).join(", ")}` : "API reachable, no generateContent models listed"
        });
        if (model) {
            results.push({
                name: "gemini-model",
                ok: models.includes(model),
                details: models.includes(model) ? `${model} is available` : `${model} is not listed by Gemini models API`
            });
        }
    }
    catch (error) {
        results.push({
            name: "gemini",
            ok: false,
            details: error instanceof Error ? error.message : String(error)
        });
    }
    return results;
}
async function checkGeminiWrapper(model, options = {}) {
    const baseUrl = readGeminiWrapperBaseUrl();
    const apiKey = readGeminiWrapperApiKey();
    const mode = readGeminiWrapperMode();
    if (mode === "python" || (!baseUrl && mode === "auto")) {
        return await checkGeminiApiBridge(model, options);
    }
    const results = [
        {
            name: "gemini-wrapper-url",
            ok: Boolean(baseUrl),
            details: baseUrl
                ? `using explicit wrapper URL ${baseUrl}`
                : "missing. Set PATCHPILOT_GEMINI_WRAPPER_BASE_URL, or use the Python bridge with explicit cookie auth."
        }
    ];
    if (!baseUrl) {
        return results;
    }
    results.push({
        name: "gemini-wrapper-key",
        ok: !geminiWrapperRequiresApiKey(baseUrl) || Boolean(apiKey),
        details: apiKey
            ? "explicit wrapper API key is configured"
            : geminiWrapperRequiresApiKey(baseUrl)
                ? "missing for remote wrapper URL. Set PATCHPILOT_GEMINI_WRAPPER_API_KEY or GEMINI_WRAPPER_API_KEY."
                : "not required for local wrapper URL"
    });
    if (geminiWrapperRequiresApiKey(baseUrl) && !apiKey) {
        return results;
    }
    try {
        const models = await new GeminiWrapperClient().listModels();
        results.push({
            name: "gemini-wrapper",
            ok: true,
            details: models.length > 0 ? `available models: ${models.slice(0, 12).join(", ")}` : "wrapper reachable, no models listed"
        });
        if (model) {
            results.push({
                name: "gemini-wrapper-model",
                ok: models.includes(model),
                details: models.includes(model) ? `${model} is available` : `${model} is not listed by the wrapper models API`
            });
        }
    }
    catch (error) {
        results.push({
            name: "gemini-wrapper",
            ok: false,
            details: error instanceof Error ? error.message : String(error)
        });
    }
    return results;
}
async function checkGeminiApiBridge(model, options = {}) {
    const pythonCommand = readGeminiWrapperPythonCommand();
    const hasExplicitAuth = Boolean(readGeminiWrapperCookiesJson() || readGeminiWrapperSecure1psid());
    const isInstalledBefore = await isGeminiWebApiInstalled(pythonCommand);
    const hasCookieImportBefore = await isGeminiBrowserCookieImportInstalled(pythonCommand);
    const isInstalled = (isInstalledBefore && hasCookieImportBefore) || (options.fix ? await ensureGeminiWebApiInstalled(pythonCommand) : false);
    const results = [
        {
            name: "gemini-api-bridge",
            ok: isInstalled,
            details: isInstalled
                ? `${isInstalledBefore && hasCookieImportBefore ? "gemini_webapi and browser-cookie3 imports work" : "installed pinned gemini_webapi and browser-cookie3 into PatchPilot managed venv"} through ${pythonCommand}`
                : options.fix
                    ? `missing. PatchPilot tried the managed venv install. Manual fallback: ${geminiWebApiInstallCommand}`
                    : `missing. Run /doctor fix or patchpilot doctor --fix to install the managed bridge. Manual fallback: ${geminiWebApiInstallCommand}`,
            action: isInstalledBefore && hasCookieImportBefore ? "check" : options.fix && isInstalled ? "fix" : "skipped"
        },
        {
            name: "gemini-api-auth",
            ok: hasExplicitAuth,
            details: hasExplicitAuth
                ? "explicit cookie auth is configured"
                : "missing. Run `patchpilot gemini-wrapper import-cookies`, set PATCHPILOT_GEMINI_WRAPPER_COOKIES_JSON, or set GEMINI_SECURE_1PSID."
        }
    ];
    if (!isInstalled || !hasExplicitAuth) {
        return results;
    }
    try {
        const client = new GeminiWrapperClient();
        await client.checkBridgeAuth();
        const models = await client.listModels();
        results.push({
            name: "gemini-api-auth-check",
            ok: true,
            details: "Gemini-API bridge auth initializes successfully"
        });
        results.push({
            name: "gemini-wrapper",
            ok: true,
            details: `Python bridge ready. Models: ${models.join(", ")}`
        });
        if (model) {
            results.push({
                name: "gemini-wrapper-model",
                ok: models.includes(model),
                details: models.includes(model) ? `${model} is available` : `${model} is not in the bridge default model list`
            });
        }
    }
    catch (error) {
        results.push({
            name: "gemini-wrapper",
            ok: false,
            details: error instanceof Error ? error.message : String(error)
        });
    }
    return results;
}
function checkCommand(command, args, name = command, missingHint) {
    return new Promise((resolve) => {
        const child = spawn(command, args, {
            windowsHide: true
        });
        let output = "";
        child.stdout.on("data", (chunk) => {
            output += chunk.toString("utf8");
        });
        child.stderr.on("data", (chunk) => {
            output += chunk.toString("utf8");
        });
        child.on("error", (error) => {
            resolve({
                name,
                ok: false,
                details: missingHint ? `${error.message}. ${missingHint}` : error.message
            });
        });
        child.on("close", (exitCode) => {
            resolve({
                name,
                ok: exitCode === 0,
                details: output.trim()
            });
        });
    });
}
//# sourceMappingURL=doctor.js.map