import { sanitizeUserVisibleOutput } from "../../util/user-visible-output.js";
import { style } from "../../theme/colors.js";
import { isUnsupportedRuntimeError, renderRouteBlockedPanel } from "./route-blocked-panel.js";
// ── Inline Markdown Renderer ──────────────────────────────────────────────
const RE_CODE_BLOCK = /^```(\w*)$/;
const RE_HEADER = /^(#{1,3})\s+(.+)$/;
const RE_LIST_ITEM = /^(\s*)[-*]\s+(.+)$/;
const RE_NUMBERED_LIST = /^(\s*)\d+\.\s+(.+)$/;
function renderInlineMarkdown(text) {
    // Bold: **text** or __text__
    let s = text.replace(/\*\*(.+?)\*\*/g, (_, m) => style.whiteBold(m));
    s = s.replace(/__(.+?)__/g, (_, m) => style.whiteBold(m));
    // Italic: *text* or _text_ (but not inside words with underscores)
    s = s.replace(/(?<!\w)\*(.+?)\*(?!\w)/g, (_, m) => style.cream(style.italic + m + style.reset));
    // Inline code: `text`
    s = s.replace(/`([^`]+)`/g, (_, m) => style.bgDark(" " + m + " "));
    // Links: [text](url) → just show text
    s = s.replace(/\[([^\]]+)\]\([^)]+\)/g, (_, m) => style.cyan(m));
    return s;
}
function renderMarkdownBlock(lines) {
    const output = [];
    let inCodeBlock = false;
    let codeLang = "";
    let codeLines = [];
    for (const line of lines) {
        // Code block toggle
        const cbMatch = line.match(RE_CODE_BLOCK);
        if (cbMatch) {
            if (inCodeBlock) {
                // End code block
                output.push(renderCodeBlock(codeLines, codeLang));
                codeLines = [];
                codeLang = "";
                inCodeBlock = false;
            }
            else {
                inCodeBlock = true;
                codeLang = cbMatch[1];
            }
            continue;
        }
        if (inCodeBlock) {
            codeLines.push(line);
            continue;
        }
        // Headers
        const hMatch = line.match(RE_HEADER);
        if (hMatch) {
            const level = hMatch[1].length;
            const text = hMatch[2];
            if (level === 1)
                output.push(style.purpleBold("▋ " + text));
            else if (level === 2)
                output.push(style.mintBold("▸ " + text));
            else
                output.push(style.cyanBold("  · " + text));
            continue;
        }
        // List items
        const lMatch = line.match(RE_LIST_ITEM) || line.match(RE_NUMBERED_LIST);
        if (lMatch) {
            const indent = lMatch[1];
            const text = lMatch[2];
            output.push(indent + style.purple("◆") + " " + renderInlineMarkdown(text));
            continue;
        }
        // Horizontal rule
        if (/^[-*_]{3,}$/.test(line.trim())) {
            output.push(style.gray("─".repeat(40)));
            continue;
        }
        // Empty line
        if (line.trim() === "") {
            output.push("");
            continue;
        }
        // Regular text with inline markdown
        output.push(renderInlineMarkdown(line));
    }
    // Unclosed code block
    if (inCodeBlock && codeLines.length > 0) {
        output.push(renderCodeBlock(codeLines, codeLang));
    }
    return output.join("\n");
}
function renderCodeBlock(codeLines, lang) {
    const maxLen = Math.max(...codeLines.map((l) => l.length), lang.length + 4);
    const width = Math.min(maxLen + 2, 76);
    const top = style.gray("┌" + "─".repeat(width) + "┐");
    const bottom = style.gray("└" + "─".repeat(width) + "┘");
    const langLabel = lang ? style.mint(" " + lang + " ") : "";
    const body = codeLines.map((l) => style.gray("│") + style.cream(" " + l.padEnd(width - 1)) + style.gray("│"));
    return [langLabel ? top.replace("─".repeat(width), "─".repeat(2) + langLabel + "─".repeat(Math.max(0, width - 2 - stripAnsiLen(langLabel)))) : top, ...body, bottom].join("\n");
}
function stripAnsiLen(s) {
    return s.replace(/\x1b\[[0-9;]*m/g, "").length;
}
// ── Thinking/Reasoning Display ─────────────────────────────────────────────
const THINK_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
let thinkFrameIdx = 0;
function renderThinkingLine(summary, elapsedMs, activity) {
    const spinner = THINK_FRAMES[thinkFrameIdx++ % THINK_FRAMES.length];
    const seconds = Math.floor(elapsedMs / 1000);
    const time = style.phosphorDim(`${seconds}s`);
    if (summary) {
        const truncated = summary.length > 60 ? summary.slice(0, 57) + "..." : summary;
        return `  ${style.purple(spinner)} ${style.gray(truncated)} ${time}`;
    }
    const active = activity ?? "routing turn · evidence gate armed";
    const truncated = active.length > 60 ? active.slice(0, 57) + "..." : active;
    return `  ${style.purple(spinner)} ${style.phosphorDim(truncated)} ${time}`;
}
// ── RichRenderer ───────────────────────────────────────────────────────────
export class RichRenderer {
    stdout;
    stderr;
    heartbeatOpen = false;
    promptOpen = false;
    thinkingSummary;
    sessionStartTime = 0;
    constructor(streams = {}) {
        this.stdout = streams.stdout ?? process.stdout;
        this.stderr = streams.stderr ?? process.stderr;
    }
    start() {
        this.sessionStartTime = Date.now();
    }
    emit(event) {
        switch (event.type) {
            case "session:start": {
                const provider = event.provider === "auto" ? "omk" : event.provider;
                const model = event.model ?? "auto";
                this.stderr.write("\n");
                this.stderr.write(style.purpleBold("  ◆ ") + style.whiteBold(provider) + style.gray(" · ") + style.cream(model) + "\n");
                this.stderr.write(style.gray("  " + "─".repeat(Math.min(provider.length + model.length + 5, 40))) + "\n\n");
                break;
            }
            case "input:submitted": {
                const text = event.text.length > 80 ? event.text.slice(0, 77) + "..." : event.text;
                if (this.promptOpen) {
                    if (!this.stderr.isTTY)
                        this.stderr.write(style.cream(text));
                    this.stderr.write("\n\n");
                    this.promptOpen = false;
                }
                else {
                    this.stderr.write(style.mint("  › ") + style.cream(text) + "\n\n");
                }
                break;
            }
            case "prompt:ready":
                if (!this.promptOpen) {
                    this.stderr.write(style.mint("  › "));
                    this.promptOpen = true;
                }
                break;
            case "control:output":
                if (this.heartbeatOpen) {
                    this.stderr.write("\r" + " ".repeat(80) + "\r");
                    this.heartbeatOpen = false;
                }
                this.stderr.write(sanitizeUserVisibleOutput(event.text));
                break;
            case "turn:route": {
                // Compact route info bar
                const parts = [];
                parts.push(style.phosphorDim("⚙ ") + style.white(event.provider));
                if (event.model)
                    parts.push(style.gray(event.model));
                if (event.risk !== "safe")
                    parts.push(style.amber(event.risk));
                if (event.sandbox !== "none")
                    parts.push(style.mint(event.sandbox));
                if (event.mcp && event.mcp.length > 0)
                    parts.push(style.cyan(`${event.mcp.length} mcp`));
                if (event.skills && event.skills.length > 0)
                    parts.push(style.violet(`${event.skills.length} skills`));
                this.stderr.write("  " + parts.join(style.gray(" · ")) + "\n");
                break;
            }
            case "turn:start":
                this.thinkingSummary = undefined;
                break;
            case "turn:heartbeat": {
                const line = renderThinkingLine(this.thinkingSummary, event.elapsedMs, event.activity);
                if (this.stderr.isTTY) {
                    this.stderr.write("\r" + line.padEnd(80) + "\r");
                    this.heartbeatOpen = true;
                }
                break;
            }
            case "assistant:final": {
                if (this.heartbeatOpen) {
                    this.stderr.write("\r" + " ".repeat(80) + "\r");
                    this.heartbeatOpen = false;
                }
                const lines = event.text.split("\n");
                const rendered = renderMarkdownBlock(lines);
                this.stdout.write(rendered + (rendered.endsWith("\n") ? "" : "\n"));
                break;
            }
            case "turn:error": {
                if (this.heartbeatOpen) {
                    this.stderr.write("\r" + " ".repeat(80) + "\r");
                    this.heartbeatOpen = false;
                }
                const errMsg = sanitizeUserVisibleOutput(event.message);
                if (isUnsupportedRuntimeError(errMsg)) {
                    this.stderr.write("\n" + renderRouteBlockedPanel(errMsg) + "\n\n");
                    break;
                }
                this.stderr.write("\n" + style.red("  ✖ ") + style.white(errMsg) + "\n\n");
                break;
            }
            case "turn:finish": {
                if (this.heartbeatOpen) {
                    this.stderr.write("\r" + " ".repeat(80) + "\r");
                    this.heartbeatOpen = false;
                }
                const secs = (event.durationMs / 1000).toFixed(1);
                this.stderr.write(style.gray("  ─ turn settled · ") + style.phosphorDim(`${secs}s`) + style.gray(" ─") + "\n\n");
                break;
            }
            case "session:stop":
                break;
        }
    }
    /** Update thinking summary from reasoning NLP (called externally) */
    setThinkingSummary(summary) {
        this.thinkingSummary = summary;
    }
    stop() { }
}
