import { pathExists, collectMcpConfigs, getProjectRoot, getUserHome } from "../../util/fs.js";
import { style } from "../../util/theme.js";
import { OMK_MATRIX_ASCII_ART } from "../../brand/omk-matrix-art.js";
import { OMK_SIMPLE_ASCII_ART } from "../../brand/omk-simple-art.js";
import { renderMatrixRain } from "../../brand/matrix-rain.js";
import { dirname, join, isAbsolute } from "path";
import { readFile, readdir } from "fs/promises";
import YAML from "yaml";
import { t } from "../../util/i18n.js";
import { getActiveRuntimePreset } from "../../util/resource-profile.js";
export function mergeTodos(existing, incoming) {
    const map = new Map();
    for (const t of existing) {
        map.set(t.title, t);
    }
    for (const t of incoming) {
        const current = map.get(t.title);
        if (current) {
            map.set(t.title, { ...current, status: t.status });
        }
        else {
            map.set(t.title, t);
        }
    }
    return Array.from(map.values());
}
export const CHAT_STARTUP_FAILURE_OUTPUT_LIMIT = 4000;
export function appendRecentChatOutput(current, data) {
    const next = current + data;
    return next.length > CHAT_STARTUP_FAILURE_OUTPUT_LIMIT
        ? next.slice(-CHAT_STARTUP_FAILURE_OUTPUT_LIMIT)
        : next;
}
export function sanitizeChatStartupFailureOutput(output) {
    return output
        .replace(/\u001b\[[0-9;]*m/g, "")
        .replace(/(authorization|api[_-]?key|token|secret|password)\s*[:=]\s*[^\s"'`]+/gi, "$1=***")
        .replace(/bearer\s+[A-Za-z0-9._~+/-]+/gi, "Bearer ***");
}
export function isKimiPromptReadyLine(line) {
    return /(?:^|\s)(?:waiting for input|ready for input|enter your prompt|prompt ready)(?:\s|$)/i.test(line)
        || /^[>›]\s*$/.test(line.trim());
}
export function formatResourceCount(count, scope) {
    return count > 0 ? `${count} active (${scope})` : style.gray(`none (${scope})`);
}
export function resolveLayout(requested) {
    if (requested && requested !== "auto")
        return requested;
    return "inline";
}
export function defaultChatUiForBrand(brand) {
    if (brand === "green-rain" || brand === "neon-grid" || brand === "rust-forge")
        return brand;
    return undefined;
}
export function resolveChatUi(requested, env = process.env) {
    const raw = requested ?? env.OMK_UI ?? env.OMK_CHAT_UI ?? "system24";
    const normalized = raw.trim().toLowerCase();
    if (normalized === "plain-modern" || normalized === "modern" || normalized === "agent-console")
        return "plain-modern";
    if (normalized === "rich")
        return "rich";
    if (normalized === "system24" || normalized === "s24")
        return "system24";
    if (normalized === "green-rain" || normalized === "green" || normalized === "matrix" || normalized === "rain")
        return "green-rain";
    if (normalized === "neon-grid" || normalized === "neon" || normalized === "grid" || normalized === "control" || normalized === "omk-control" || normalized === "night-city" || normalized === "metrics-control")
        return "neon-grid";
    if (normalized === "rust-forge" || normalized === "rust" || normalized === "cargo" || normalized === "oxide" || normalized === "forge")
        return "rust-forge";
    return "legacy";
}
export function resolveChatWorkerCount(requested, fallback) {
    const trimmed = requested?.trim();
    if (!trimmed || trimmed.toLowerCase() === "auto") {
        return String(Math.max(1, fallback));
    }
    return trimmed;
}
export function renderChatIntro(brand, meta) {
    const titleKey = {
        omk: "chat.intro.omk",
        "green-rain": "chat.intro.greenRain",
        "neon-grid": "chat.intro.neonGrid",
        "rust-forge": "chat.intro.rustForge",
        minimal: "chat.intro.minimal",
        plain: "chat.intro.plain",
    };
    const title = t(titleKey[brand] ?? titleKey.omk);
    const lines = [];
    if (brand === "green-rain") {
        const rainWidth = Math.min(60, process.stdout.columns ?? 80);
        const rain = renderMatrixRain(meta.runId ?? "omk", rainWidth, 4);
        for (const rainLine of rain.split("\n")) {
            lines.push(style.phosphor(rainLine));
        }
        lines.push("");
        for (const artLine of OMK_MATRIX_ASCII_ART.split("\n")) {
            lines.push(style.phosphor(artLine));
        }
        lines.push("");
    }
    else if (brand === "rust-forge") {
        lines.push(style.rustBold("▣ OMK//RUST-FORGE"));
        lines.push(style.gray("  CARGO SAFETY ONLINE"));
        lines.push(style.gray("  Native: hot · Verify: armed · Loop: controlled."));
        for (const artLine of OMK_SIMPLE_ASCII_ART.split("\n")) {
            lines.push(style.rust(artLine));
        }
        lines.push("");
    }
    else if (brand !== "plain") {
        lines.push(style.phosphorBold("◇ OMK//CONTROL"));
        lines.push(style.gray("  OMK ONLINE"));
        lines.push(style.gray("  Route: online · Verify: armed · Loop: controlled."));
        lines.push("");
    }
    lines.push(style.phosphorBold(`▸ ${title}`));
    if (brand !== "plain") {
        lines.push(`  ${style.gray(t("chat.intro.agent") + ":")} ${style.cream(meta.agent)}`);
        if (meta.runId) {
            lines.push(`  ${style.gray(t("chat.intro.run") + ":")} ${style.cream(meta.runId)}`);
        }
        lines.push(`  ${style.gray(t("chat.intro.layout") + ":")} ${style.cream(meta.layout)}`);
        lines.push(`  ${style.gray(t("chat.intro.trust") + ":")} ${style.cream(meta.trust)}`);
        if (meta.mode) {
            lines.push(`  ${style.gray("Mode:")} ${style.cream(meta.mode)}`);
        }
    }
    return lines.join("\n");
}
export async function verifyAgentPrompt(agentFile) {
    if (!(await pathExists(agentFile)))
        return false;
    try {
        const raw = await readFile(agentFile, "utf8");
        const parsed = YAML.parse(raw);
        const promptPath = parsed?.agent?.system_prompt_path;
        if (!promptPath)
            return true;
        const resolved = isAbsolute(promptPath)
            ? promptPath
            : join(dirname(agentFile), promptPath);
        return await pathExists(resolved);
    }
    catch {
        return false;
    }
}
export async function getActiveMcpNames(scope) {
    if (scope === "none")
        return [];
    const configs = await collectMcpConfigs(scope);
    const results = await Promise.all(configs.map(async (cfg) => {
        try {
            const raw = await readFile(cfg, "utf-8");
            const parsed = JSON.parse(raw);
            return parsed.mcpServers ? Object.keys(parsed.mcpServers) : [];
        }
        catch {
            return [];
        }
    }));
    return [...new Set(["omk-project", ...results.flat()])];
}
export async function getActiveSkillNames(skillsScope) {
    if (skillsScope === "none")
        return [];
    const dirs = [];
    const projectDir = join(getProjectRoot(), ".agents", "skills");
    if (await pathExists(projectDir))
        dirs.push(projectDir);
    if (skillsScope === "all") {
        const globalDir = join(getUserHome(), ".agents", "skills");
        if (await pathExists(globalDir))
            dirs.push(globalDir);
    }
    const results = await Promise.all(dirs.map(async (dir) => {
        try {
            const entries = await readdir(dir, { withFileTypes: true });
            return entries.filter((e) => e.isDirectory()).map((e) => e.name);
        }
        catch {
            return [];
        }
    }));
    const discovered = [...new Set(results.flat())];
    if (skillsScope === "all")
        return discovered;
    const activePreset = await getActiveRuntimePreset();
    return activePreset ? discovered.filter((name) => activePreset.skills.includes(name)) : discovered;
}
export async function getActiveHookNames(root, hooksScope) {
    if (hooksScope === "none")
        return [];
    try {
        const { discoverRoutingInventory } = await import("../../orchestration/routing/inventory.js");
        const discovered = [...discoverRoutingInventory(root).hooks.keys()];
        if (hooksScope === "all")
            return discovered;
        const activePreset = await getActiveRuntimePreset();
        return activePreset ? discovered.filter((name) => activePreset.hooks.includes(name)) : discovered;
    }
    catch {
        return [];
    }
}
