import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Box, Text } from "ink";
import { Divider } from "./design/Divider.js";
import { StatusBadge } from "./design/StatusBadge.js";
import { truncateCells } from "./design/textLayout.js";
import { toneColor } from "./design/terminalTheme.js";
export function LogSelector(props) {
    const width = Math.max(44, props.width);
    return (_jsxs(Box, { flexDirection: "column", marginTop: 1, marginBottom: 1, children: [_jsx(Divider, { width: Math.max(12, width - 2), title: props.model.title, tone: "muted" }), _jsx(Text, { color: "gray", children: truncateCells(props.model.summary, Math.max(20, width - 4)) }), _jsx(Box, { flexDirection: "row", marginTop: 1, children: props.model.levels.map((level) => (_jsx(Box, { marginRight: 1, children: _jsx(StatusBadge, { label: `${level.level} ${level.count}`, tone: level.count > 0 ? level.tone : "muted" }) }, level.level))) }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: props.model.rows.length === 0 ? (_jsx(Text, { color: "gray", children: "No matching logs" })) : props.model.rows.map((row) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: toneColor(row.selected ? "brand" : "muted"), children: [row.marker, " "] }), _jsx(StatusBadge, { label: row.level, tone: row.tone }), _jsx(Text, { color: "gray", children: " " }), _jsx(Text, { color: toneColor(row.tone), children: truncateCells(row.message, Math.max(16, width - 20)) })] }), row.meta ? (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: truncateCells(row.meta, Math.max(16, width - 8)) }) })) : null] }, row.key))) }), _jsx(Text, { color: "gray", children: truncateCells(props.model.footer, Math.max(20, width - 4)) })] }));
}
export function logSelectorModel(logs, options = {}) {
    const query = options.query?.trim().toLowerCase() ?? "";
    const visibleCount = Math.max(1, options.visibleCount ?? 6);
    const filtered = query ? logs.filter((record) => logMatches(record, query)) : logs;
    const selectedIndex = selectedLogIndex(filtered, options.selectedIndex);
    const start = Math.max(0, Math.min(selectedIndex - Math.floor(visibleCount / 2), filtered.length - visibleCount));
    const visible = filtered.slice(start, start + visibleCount);
    const hiddenBefore = start;
    const hiddenAfter = Math.max(0, filtered.length - start - visible.length);
    return {
        title: options.title ?? "log selector",
        summary: logSelectorSummary(logs.length, filtered.length, hiddenBefore, hiddenAfter, query),
        levels: logSelectorLevelCounts(logs),
        rows: visible.map((record, index) => logSelectorRow(record, start + index, start + index === selectedIndex)),
        footer: query ? "/logs [limit] clears the filter" : "/doctor diagnostics | /trace <run-id|attached>",
    };
}
export function logSelectorLevelCounts(logs) {
    const counts = {
        debug: 0,
        info: 0,
        warn: 0,
        error: 0,
    };
    for (const log of logs)
        counts[log.level] += 1;
    return ["error", "warn", "info", "debug"].map((level) => ({
        level,
        count: counts[level],
        tone: toneForLogLevel(level),
    }));
}
function logSelectorRow(record, index, selected) {
    return {
        key: `${record.createdAtMs}-${index}`,
        marker: selected ? ">" : " ",
        level: record.level,
        tone: toneForLogLevel(record.level),
        message: firstLine(record.message, 160),
        meta: formatLogMeta(record),
        selected,
    };
}
function selectedLogIndex(logs, selectedIndex) {
    if (logs.length === 0)
        return 0;
    if (selectedIndex !== undefined)
        return Math.max(0, Math.min(logs.length - 1, selectedIndex));
    const important = findLastIndex(logs, (record) => record.level === "error" || record.level === "warn");
    return important >= 0 ? important : logs.length - 1;
}
function findLastIndex(items, predicate) {
    for (let index = items.length - 1; index >= 0; index -= 1) {
        if (predicate(items[index]))
            return index;
    }
    return -1;
}
function logMatches(record, query) {
    return [
        record.level,
        record.message,
        formatLogMeta(record),
    ].some((value) => value.toLowerCase().includes(query));
}
function logSelectorSummary(total, filtered, hiddenBefore, hiddenAfter, query) {
    const filter = query ? ` / query="${query}"` : "";
    const hidden = [
        hiddenBefore > 0 ? `${hiddenBefore} older` : "",
        hiddenAfter > 0 ? `${hiddenAfter} newer` : "",
    ].filter(Boolean).join(" / ");
    return hidden
        ? `${filtered}/${total} logs${filter} / hidden ${hidden}`
        : `${filtered}/${total} logs${filter}`;
}
function formatLogMeta(record) {
    const parts = [formatTime(record.createdAtMs)];
    if (record.metadata !== undefined)
        parts.push(safeJson(record.metadata));
    return parts.filter(Boolean).join(" | ");
}
function toneForLogLevel(level) {
    if (level === "error")
        return "error";
    if (level === "warn")
        return "warning";
    if (level === "info")
        return "brand";
    return "muted";
}
function firstLine(value, max) {
    const line = value.split(/\r?\n/)[0]?.trim() ?? "";
    return line.length > max ? `${line.slice(0, Math.max(0, max - 3))}...` : line;
}
function formatTime(value) {
    if (!Number.isFinite(value) || value <= 0)
        return "";
    return new Date(value).toISOString().replace("T", " ").replace(/\.\d+Z$/, "Z");
}
function safeJson(value) {
    try {
        const rendered = typeof value === "string" ? value : JSON.stringify(value);
        return rendered ?? "";
    }
    catch {
        return String(value);
    }
}
