/**
 * olam init — Initialize olam configuration in the current project.
 *
 * Delegates to the same init logic as the MCP server's olam_init tool.
 * Works without an existing OlamContext (that is the whole point).
 *
 * B6 (Phase 2 dogfood recovery): auto-write host.kubectl_context_pinned to
 * ~/.olam/config.json when exactly ONE ^k3d-olam- context is detected.
 * Decision #7: regex ^k3d-olam- (not ^k3d-) to avoid false-positives.
 * Multiple matches → stderr error, skip. Zero matches → silent skip.
 * Existing value → never overwrite.
 */
import * as fs from "node:fs";
import * as path from "node:path";
import { execSync } from "node:child_process";
import { randomUUID } from "node:crypto";
import pc from "picocolors";
import { printError, printInfo, printHeader } from "../output.js";
import { ensureProjectWorkspaceFromConfig } from "./workspace.js";
import { OLAM_CONFIG_PATH } from "../lib/config.js";
function detectProjectType(root) {
    if (fs.existsSync(path.join(root, "Gemfile")) ||
        fs.existsSync(path.join(root, "config", "routes.rb")))
        return "rails";
    if (fs.existsSync(path.join(root, "package.json")))
        return "node";
    if (fs.existsSync(path.join(root, "pyproject.toml")) ||
        fs.existsSync(path.join(root, "requirements.txt")))
        return "python";
    return "generic";
}
function getRepoName(root) {
    try {
        const url = execSync("git remote get-url origin", {
            cwd: root,
            encoding: "utf-8",
        }).trim();
        const match = url.match(/\/([^/]+?)(?:\.git)?$/);
        if (match)
            return match[1];
    }
    catch {
        /* fallback */
    }
    return path.basename(root);
}
/**
 * Detect `^k3d-olam-` kubectl contexts from the operator's kubeconfig.
 *
 * Returns:
 *   { contexts: string[] } — list of matching context names (may be empty).
 *   { contexts: null }     — kubectl not found / kubeconfig unreadable (skip silently).
 *
 * Exported for unit testing.
 */
export function detectK3dOlamContexts(execFn = (cmd, opts) => execSync(cmd, opts)) {
    try {
        const raw = execFn("kubectl config get-contexts -o name", {
            encoding: "utf-8",
        });
        const contexts = raw
            .split("\n")
            .map((l) => l.trim())
            .filter((l) => /^k3d-olam-/.test(l));
        return { contexts };
    }
    catch {
        // kubectl not found or kubeconfig unreadable — skip silently
        return { contexts: null };
    }
}
/**
 * Write host.kubectl_context_pinned to ~/.olam/config.json when exactly one
 * ^k3d-olam- context is detected. Reads the file raw so unknown fields are
 * preserved (OlamConfig strict type doesn't include kubectl_context_pinned).
 *
 * Returns:
 *   { pinned: string }  — field written.
 *   { skipped: string } — reason it was not written (informational; not an error).
 *   { refused: string } — multiple contexts detected (emit to stderr).
 *
 * Exported for unit testing.
 */
export function applyKubectlContextPin(contexts, opts = {}) {
    const configPath = opts.configPath ?? OLAM_CONFIG_PATH;
    const readFn = opts.readFileSyncFn ?? fs.readFileSync;
    const writeFn = opts.writeFileSyncFn ?? fs.writeFileSync;
    const mkdirFn = opts.mkdirSyncFn ?? fs.mkdirSync;
    if (contexts.length === 0) {
        return { skipped: "no ^k3d-olam- contexts found" };
    }
    if (contexts.length > 1) {
        return {
            refused: `multiple ^k3d-olam- contexts found: ${contexts.join(", ")} — set host.kubectl_context_pinned manually`,
        };
    }
    const context = contexts[0];
    // Read existing config raw to preserve unknown fields (kubectl_context_pinned
    // is not in OlamConfig strict type; we patch the JSON directly).
    let parsed = {};
    try {
        const raw = readFn(configPath, "utf8");
        parsed = JSON.parse(raw);
    }
    catch {
        // File absent or malformed — seed a schema-valid baseline so readConfig
        // won't overwrite kubectl_context_pinned when it validates the schema later.
        // Mirrors makeDefaultConfig() in config.ts.
        parsed = {
            "config.schema": 1,
            host: { substrate: "kubernetes" },
            install_id: randomUUID(),
        };
    }
    const host = typeof parsed.host === "object" && parsed.host !== null
        ? parsed.host
        : {};
    // Never overwrite an existing value.
    if (typeof host["kubectl_context_pinned"] === "string" &&
        host["kubectl_context_pinned"].length > 0) {
        return {
            skipped: `kubectl_context_pinned already set to ${host["kubectl_context_pinned"]}`,
        };
    }
    const next = {
        ...parsed,
        host: { ...host, kubectl_context_pinned: context },
    };
    // Ensure parent dir exists (e.g. ~/.olam/ may not exist on fresh machines
    // where Phase 2.6 runs before any other step that would create it).
    mkdirFn(path.dirname(configPath), { recursive: true });
    writeFn(configPath, JSON.stringify(next, null, 2) + "\n", {
        encoding: "utf8",
    });
    return { pinned: context };
}
/**
 * Walk UP from `startDir` to the nearest `.git` directory; return that root
 * (or `startDir` if no .git is found en route to filesystem root).
 *
 * Exported so `olam setup` Phase 5 can resolve `.olam/config.yaml` using
 * the SAME walk semantics as `olam init` — otherwise re-running setup
 * from a subdir of a git repo fails Phase 5's idempotency contract
 * (audit finding HIGH on Phase C CP3).
 */
export function findProjectRoot(startDir) {
    let current = path.resolve(startDir);
    while (true) {
        if (fs.existsSync(path.join(current, ".git")))
            return current;
        const parent = path.dirname(current);
        if (parent === current)
            return startDir;
        current = parent;
    }
}
export function registerInit(program) {
    program
        .command("init")
        .description("Initialize olam in the current project")
        .option("--path <path>", "Project root path", process.cwd())
        .option("--skip-pleri", "Skip Pleri setup")
        .action(async (opts) => {
        try {
            const projectRoot = findProjectRoot(opts.path);
            const olamDir = path.join(projectRoot, ".olam");
            if (fs.existsSync(path.join(olamDir, "config.yaml"))) {
                printError(`Already initialized at ${olamDir}/config.yaml`);
                process.exitCode = 1;
                return;
            }
            const projectType = detectProjectType(projectRoot);
            const repoName = getRepoName(projectRoot);
            let remoteUrl;
            try {
                remoteUrl = execSync("git remote get-url origin", {
                    cwd: projectRoot,
                    encoding: "utf-8",
                }).trim();
            }
            catch {
                remoteUrl = `git@github.com:your-org/${repoName}.git`;
            }
            fs.mkdirSync(path.join(olamDir, "state"), { recursive: true });
            fs.mkdirSync(path.join(olamDir, "thoughts"), { recursive: true });
            const pleriSection = opts.skipPleri
                ? "# pleri:\n#   base_url: ${PLERI_BASE_URL}\n#   plane_id: ${PLERI_PLANE_ID}\n#   api_key: ${PLERI_API_KEY}\n"
                : "pleri:\n  base_url: ${PLERI_BASE_URL}\n  plane_id: ${PLERI_PLANE_ID}\n  api_key: ${PLERI_API_KEY}\n";
            const config = [
                "version: 2",
                "",
                pleriSection,
                "repos:",
                `  - name: ${repoName}`,
                `    url: ${remoteUrl}`,
                `    path: ${projectRoot}`,
                `    type: ${projectType}`,
                "    services: []",
                "",
                "compute:",
                "  default: docker",
                "",
                "cost:",
                "  # All values in USD (Anthropic's billing currency).",
                "  # Convert from your local currency: USD 25 ≈ SGD 33 / EUR 23 / GBP 20",
                "  # at typical 2026 rates. Dashboard display localization is a future feature.",
                "  max_per_world_usd: 25",
                "  max_daily_usd: 100",
                "  warning_threshold: 0.8",
                "",
                "auth:",
                "  mode: oauth",
                "",
            ].join("\n");
            fs.writeFileSync(path.join(olamDir, "config.yaml"), config);
            const envExample = [
                "# Pleri credentials",
                "PLERI_BASE_URL=https://pleri.dev/api",
                "PLERI_PLANE_ID=",
                "PLERI_API_KEY=",
                "",
            ].join("\n");
            fs.writeFileSync(path.join(olamDir, ".env.example"), envExample);
            printHeader("Olam initialized");
            printInfo("Config", `${olamDir}/config.yaml`);
            printInfo("Project", `${projectType} (detected)`);
            printInfo("Repo", repoName);
            // Auto-register this project as a host-catalog workspace so
            // `olam create --workspace <repo>` works from anywhere. Tolerant
            // of failure — init must not bail just because workspace write
            // hit a permissions issue or similar edge case.
            try {
                const result = ensureProjectWorkspaceFromConfig(projectRoot, repoName);
                if (result.created) {
                    printInfo("Workspace", `${repoName} → ${result.file}`);
                }
                else {
                    printInfo("Workspace", `${repoName} (already registered)`);
                }
            }
            catch (err) {
                printError(`Workspace auto-register failed: ${err instanceof Error ? err.message : String(err)}`);
            }
            // B6: auto-pin kubectl context if exactly one ^k3d-olam- context detected.
            const { contexts } = detectK3dOlamContexts();
            if (contexts !== null) {
                const pinResult = applyKubectlContextPin(contexts);
                if ("pinned" in pinResult) {
                    printInfo("kubectl context", `${pinResult.pinned} (auto-pinned)`);
                }
                else if ("refused" in pinResult) {
                    process.stderr.write(`${pc.yellow("warn:")} ${pinResult.refused}\n`);
                }
                // skipped → silent
            }
            console.log(`\n${pc.dim(`Next: olam create --name my-world --workspace ${repoName} --task "..."`)}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : String(err));
            process.exitCode = 1;
        }
    });
}
//# sourceMappingURL=init.js.map