import { getRunPath, pathExists } from "../../util/fs.js";
import { relative } from "path";
import { style, status, box, label, separator } from "../../util/theme.js";
import { writeSessionMeta } from "../../util/session.js";
import { finalizeChatState } from "../../util/chat-state.js";
import { getOmkResourceSettings } from "../../util/resource-profile.js";
import { buildOmkToolPlaneManifest } from "../../runtime/tool-plane.js";
import { sanitizeChatStartupFailureOutput, CHAT_STARTUP_FAILURE_OUTPUT_LIMIT, formatResourceCount, getActiveMcpNames, getActiveSkillNames, } from "./utils.js";
export async function buildChatSmokeReport(options) {
    const toolPlane = await buildOmkToolPlaneManifest({
        mcpScope: options.mcpScope,
        mcpAllowlist: options.mcpAllowlist,
    });
    const runtimeMcpPath = toolPlane.mcpConfigFile ?? null;
    const runtimeMcpExists = runtimeMcpPath ? await pathExists(runtimeMcpPath) : false;
    const failurePath = getRunPath(options.runId, "chat-startup-failure.json", options.root);
    const startupFailureArtifactExists = await pathExists(failurePath);
    const toolPlaneErrorCount = toolPlane.diagnostics.filter((diagnostic) => diagnostic.level === "error").length;
    const toolPlaneWarningCount = toolPlane.diagnostics.filter((diagnostic) => diagnostic.level === "warning").length;
    const checks = [
        {
            name: "agent schema",
            status: options.schemaOk ? "ok" : "fail",
            message: options.schemaOk ? "agent YAML schema is valid" : "agent YAML schema is invalid",
        },
        {
            name: "runtime MCP merge",
            status: options.mcpScope === "none" || runtimeMcpExists ? "ok" : "fail",
            message: runtimeMcpPath
                ? `runtime MCP config: ${relative(options.root, runtimeMcpPath)}`
                : options.mcpScope === "none"
                    ? "MCP disabled by scope none"
                    : "runtime MCP config was not generated",
        },
        {
            name: "startup failure artifact",
            status: startupFailureArtifactExists ? "fail" : "ok",
            message: startupFailureArtifactExists ? "chat-startup-failure.json exists" : "no startup failure artifact",
        },
        {
            name: "tool-plane diagnostics",
            status: toolPlaneErrorCount > 0 ? "fail" : "ok",
            message: toolPlane.diagnostics.length === 0
                ? "no tool-plane diagnostics"
                : `${toolPlaneErrorCount} error(s), ${toolPlaneWarningCount} warning(s)`,
        },
    ];
    return {
        ok: checks.every((check) => check.status === "ok"),
        command: "chat smoke",
        runId: options.runId,
        agentFile: relative(options.root, options.agentFile),
        schemaOk: options.schemaOk,
        mcpScope: options.mcpScope,
        skillsScope: options.resources.skillsScope,
        hooksScope: options.resources.hooksScope,
        runtimeMcpConfig: {
            injected: Boolean(runtimeMcpPath),
            path: runtimeMcpPath ? relative(options.root, runtimeMcpPath) : null,
            exists: runtimeMcpExists,
        },
        root: {
            path: options.root,
            cwd: options.activeCwd ?? process.cwd(),
            source: options.rootSource ?? "unknown",
        },
        diagnostics: {
            toolPlane: toolPlane.diagnostics,
        },
        startupFailureArtifactExists,
        checks,
    };
}
export async function writeChatStartupFailureArtifact(options) {
    const artifactPath = getRunPath(options.runId, "chat-startup-failure.json", options.root);
    const artifact = {
        runId: options.runId,
        exitCode: options.exitCode,
        capturedAt: new Date().toISOString(),
        agentFile: relative(options.root, options.agentFile),
        mcpScope: options.resources.mcpScope,
        skillsScope: options.resources.skillsScope,
        hooksScope: options.resources.hooksScope,
        reason: options.reason,
        schemaIssues: options.schemaIssues ?? [],
        recentOutput: sanitizeChatStartupFailureOutput(options.recentOutput).slice(-CHAT_STARTUP_FAILURE_OUTPUT_LIMIT),
    };
    await import("fs/promises").then(({ writeFile }) => writeFile(artifactPath, JSON.stringify(artifact, null, 2) + "\n", "utf-8"));
}
export async function failChatBeforeLaunch(options) {
    const detail = options.schemaIssues?.length
        ? `\n${options.schemaIssues.slice(0, 8).map((item) => `  - ${item}`).join("\n")}`
        : "";
    console.error(status.error(`[omk] ${options.message}`));
    if (detail)
        console.error(detail);
    console.error(style.gray("Fix: run `omk doctor --fix`, then retry `omk chat`."));
    await writeChatStartupFailureArtifact({
        root: options.root,
        runId: options.runId,
        exitCode: 1,
        agentFile: options.agentFile,
        recentOutput: `${options.message}${detail}`,
        resources: options.resources,
        reason: options.message,
        schemaIssues: options.schemaIssues,
    }).catch(() => { });
    await finalizeChatState(options.runId, false).catch(() => { });
    const now = new Date().toISOString();
    await writeSessionMeta(options.runId, {
        runId: options.runId,
        type: "chat",
        status: "failed",
        startedAt: now,
        endedAt: now,
        updatedAt: now,
        todoCount: 0,
        todoDoneCount: 0,
    }).catch(() => { });
    process.exit(1);
}
export async function printChatExitBanner(options) {
    const { runId, sessionId, kimiSessionId, workers } = options;
    const resources = await getOmkResourceSettings();
    const mcpScope = options.mcpScope ?? resources.mcpScope;
    // Parallel discovery of MCP + skills
    const [mcpNames, skillNames] = await Promise.all([
        getActiveMcpNames(mcpScope),
        getActiveSkillNames(resources.skillsScope),
    ]);
    const mcpText = formatResourceCount(mcpNames.length, mcpScope);
    const skillText = formatResourceCount(skillNames.length, resources.skillsScope);
    const workersText = workers ?? resources.maxWorkers.toString();
    const lines = [
        "",
        style.phosphorBold("  ◈ Session Closed"),
        separator(50),
        label("Run ID", runId),
        label("OMK Session", sessionId),
        ...(kimiSessionId ? [label("Provider Session", kimiSessionId)] : []),
        label("Resume", `omk runs`),
        label("Workers", workersText),
        label("MCP", mcpText),
        label("Skills", skillText),
        separator(50),
        style.gray(`  Run ${style.cream("omk hud")} for dashboard, ${style.cream("omk runs")} for history.`),
        "",
    ];
    console.log(box(lines));
}
