import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { Box, Text } from 'ink';
import { marked } from 'marked';
const HEADING_COLORS = ['cyan', 'green', 'yellow', 'magenta', 'blue', 'red'];
// Tiny, dependency-free token-class colorizer for common languages.
// Goal: useful visual separation, NOT correctness. Anything we don't
// recognise renders unstyled.
const KEYWORDS = {
    js: /\b(const|let|var|function|return|if|else|for|while|class|new|await|async|import|export|from|as|of|in|typeof|instanceof|this|super|extends|throw|try|catch|finally|switch|case|break|continue|null|undefined|true|false)\b/g,
    ts: /\b(const|let|var|function|return|if|else|for|while|class|new|await|async|import|export|from|as|of|in|typeof|instanceof|this|super|extends|throw|try|catch|finally|switch|case|break|continue|null|undefined|true|false|interface|type|enum|public|private|protected|readonly|implements|namespace)\b/g,
    py: /\b(def|class|return|if|elif|else|for|while|in|not|and|or|None|True|False|import|from|as|try|except|finally|raise|with|lambda|yield|global|nonlocal|pass|break|continue|async|await)\b/g,
    sh: /\b(if|then|fi|else|elif|for|while|do|done|case|esac|in|function|return|exit|break|continue|local|export|readonly|set|unset)\b/g,
    bash: /\b(if|then|fi|else|elif|for|while|do|done|case|esac|in|function|return|exit|break|continue|local|export|readonly|set|unset)\b/g,
    go: /\b(func|var|const|type|struct|interface|return|if|else|for|range|switch|case|default|break|continue|go|defer|chan|select|package|import|map|nil|true|false)\b/g,
};
// marked emits `language-foo` from fences; common spellings to canonical
// keys above. Without this, ```typescript ``` blocks didn't colour
// because the lookup was for `typescript` not `ts`.
const LANG_ALIASES = {
    javascript: 'js', jsx: 'js', node: 'js',
    typescript: 'ts', tsx: 'ts',
    python: 'py', python3: 'py',
    shell: 'sh', bash: 'sh', zsh: 'sh',
    golang: 'go',
};
function highlightCode(code, lang) {
    const lc = lang?.toLowerCase();
    const canon = lc ? (LANG_ALIASES[lc] ?? lc) : undefined;
    const kw = canon ? KEYWORDS[canon] : undefined;
    if (!kw)
        return [{ text: code }];
    const spans = [];
    let last = 0;
    // Reset lastIndex since we use the same RegExp instance.
    kw.lastIndex = 0;
    let m;
    // biome-ignore lint/suspicious/noAssignInExpressions: standard regex.exec loop
    while ((m = kw.exec(code)) !== null) {
        if (m.index > last)
            spans.push({ text: code.slice(last, m.index) });
        spans.push({ text: m[0], kind: 'keyword' });
        last = m.index + m[0].length;
    }
    if (last < code.length)
        spans.push({ text: code.slice(last) });
    return spans;
}
function spanColor(kind) {
    if (kind === 'keyword')
        return 'magenta';
    if (kind === 'string')
        return 'green';
    if (kind === 'comment')
        return 'gray';
    if (kind === 'number')
        return 'yellow';
    return undefined;
}
function renderInline(tokens, keyPrefix) {
    if (!tokens)
        return [];
    const out = [];
    tokens.forEach((tok, i) => {
        const k = `${keyPrefix}-${i}`;
        switch (tok.type) {
            case 'text':
                out.push(_jsx(Text, { children: tok.text ?? '' }, k));
                break;
            case 'strong':
                out.push(_jsx(Text, { bold: true, children: renderInline(tok.tokens, k) }, k));
                break;
            case 'em':
                out.push(_jsx(Text, { italic: true, children: renderInline(tok.tokens, k) }, k));
                break;
            case 'del':
                out.push(_jsx(Text, { strikethrough: true, children: renderInline(tok.tokens, k) }, k));
                break;
            case 'codespan':
                out.push(_jsxs(Text, { color: "cyan", children: ["`", tok.text ?? '', "`"] }, k));
                break;
            case 'link':
                out.push(_jsxs(Text, { children: [_jsx(Text, { underline: true, children: renderInline(tok.tokens, k) }), _jsxs(Text, { dimColor: true, children: [" (", tok.href ?? '', ")"] })] }, k));
                break;
            case 'br':
                out.push(_jsx(Text, { children: '\n' }, k));
                break;
            default:
                out.push(_jsx(Text, { children: tok.text ?? '' }, k));
        }
    });
    return out;
}
function renderBlock(tok, key) {
    switch (tok.type) {
        case 'heading': {
            const depth = Math.min((tok.depth ?? 1) - 1, HEADING_COLORS.length - 1);
            const prefix = '#'.repeat(tok.depth ?? 1) + ' ';
            return (_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: HEADING_COLORS[depth], children: prefix }), _jsx(Text, { bold: true, color: HEADING_COLORS[depth], children: renderInline(tok.tokens, key) })] }, key));
        }
        case 'paragraph':
            return (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: renderInline(tok.tokens, key) }) }, key));
        case 'code': {
            const lang = tok.lang || '';
            const spans = highlightCode(tok.text ?? '', lang);
            return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, borderStyle: "round", borderColor: "gray", paddingX: 1, children: [lang && _jsx(Text, { dimColor: true, children: lang }), _jsx(Text, { children: spans.map((s, i) => (_jsx(Text, { color: spanColor(s.kind), children: s.text }, i))) })] }, key));
        }
        case 'blockquote':
            return (_jsx(Box, { marginBottom: 1, flexDirection: "column", children: (tok.tokens ?? []).map((inner, i) => (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "\u2502 " }), _jsx(Text, { dimColor: true, children: renderInline(inner.tokens, `${key}-${i}`) })] }, i))) }, key));
        case 'list': {
            const ordered = !!tok.ordered;
            const items = (tok.items ?? []);
            return (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: items.map((item, i) => {
                    const marker = ordered ? `${i + 1}. ` : '• ';
                    // list_item tokens have nested tokens; flatten to inline text.
                    const itemTokens = item.tokens ?? [];
                    return (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: marker }), _jsx(Text, { children: renderInline(itemTokens, `${key}-${i}`) })] }, i));
                }) }, key));
        }
        case 'hr':
            return _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: '─'.repeat(40) }) }, key);
        case 'space':
            return null;
        default:
            // Tables / html / footnotes / etc. — fall back to raw text so
            // nothing is silently dropped.
            return (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: tok.text ?? '' }) }, key));
    }
}
/** Render arbitrary markdown source as Ink components. */
export function Markdown({ source }) {
    // Empty body: just nothing.
    if (!source)
        return _jsx(Text, {});
    let tokens;
    try {
        tokens = marked.lexer(source);
    }
    catch {
        // Fallback: render as plain text if the lexer chokes (e.g. partial
        // mid-stream content with unbalanced backticks).
        return _jsx(Text, { children: source });
    }
    return _jsx(_Fragment, { children: tokens.map((t, i) => renderBlock(t, `b-${i}`)) });
}
//# sourceMappingURL=markdown.js.map