import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React from "react";
import { renderToString } from "ink";
import { describe, expect, it, vi } from "vitest";
import stripAnsi from "strip-ansi";
import stringWidth from "string-width";
import { createTerminalHistoryPrinter, serializeCompletedItemToTerminalHistory, } from "./terminal-history.js";
import { isActiveItem } from "./item-helpers.js";
import { loadTheme, ThemeContext } from "./theme/theme.js";
import { TerminalSizeProvider } from "./hooks/useTerminalSize.js";
import { Text, Box } from "ink";
// BLACK_CIRCLE is platform-dependent (⏺ on macOS, ● elsewhere); pin it so
// the hardcoded frame expectations pass on Linux/Windows CI too.
vi.mock("./constants/figures.js", async (importOriginal) => ({
    ...(await importOriginal()),
    BLACK_CIRCLE: "\u23FA",
}));
import { ChatLivePane } from "./components/ChatLivePane.js";
import { AssistantMessage } from "./components/AssistantMessage.js";
import { QueuedRow } from "./transcript/MiscRows.js";
const TERMINAL_COLUMNS = 68;
const theme = loadTheme("dark");
const context = {
    theme,
    columns: TERMINAL_COLUMNS,
    version: "test",
    model: "test-model",
    provider: "anthropic",
    cwd: "/tmp/test",
};
function queuedItem(overrides = {}) {
    return {
        kind: "queued",
        text: "follow-up prompt with enough words to prove wrapping stays in the same response gutter",
        id: "queued-1",
        ...overrides,
    };
}
function renderQueuedLiveItem(item, itemTheme) {
    const imageSuffix = item.imageCount
        ? ` (+${item.imageCount} image${item.imageCount > 1 ? "s" : ""})`
        : "";
    const videoSuffix = item.videoCount
        ? ` (+${item.videoCount} video${item.videoCount > 1 ? "s" : ""})`
        : "";
    const suffix = `${imageSuffix}${videoSuffix}`;
    return (_jsxs(Box, { flexDirection: "row", paddingLeft: 1, marginTop: 1, flexShrink: 1, children: [_jsx(Box, { width: 2, flexShrink: 0, children: _jsx(Text, { color: itemTheme.warning, bold: true, children: "• " }) }), _jsx(Box, { flexDirection: "column", flexGrow: 1, children: _jsxs(Text, { color: itemTheme.text, wrap: "wrap", children: [_jsx(Text, { color: itemTheme.textDim, children: "Queued: " }), item.text || "(empty)", suffix] }) })] }));
}
function cleanLines(value) {
    return stripAnsi(value)
        .replace(/\r/g, "\n")
        .split("\n")
        .filter((line) => line.length > 0);
}
function rawLines(value) {
    return stripAnsi(value).replace(/\r/g, "\n").split("\n");
}
function trimTrailingEmptyLines(lines) {
    const next = [...lines];
    while (next.at(-1) === "")
        next.pop();
    return next;
}
function renderLiveQueuedLines(item) {
    const originalColumns = process.stdout.columns;
    const originalRows = process.stdout.rows;
    process.stdout.columns = TERMINAL_COLUMNS;
    process.stdout.rows = 20;
    try {
        return cleanLines(renderToString(_jsx(ThemeContext.Provider, { value: theme, children: _jsx(TerminalSizeProvider, { children: renderQueuedLiveItem(item, theme) }) }), { columns: TERMINAL_COLUMNS }));
    }
    finally {
        process.stdout.columns = originalColumns;
        process.stdout.rows = originalRows;
    }
}
function renderHistoryQueuedLines(item) {
    return cleanLines(serializeCompletedItemToTerminalHistory(item, context));
}
function renderQueueIndicatorLines(queuedCount, marginTop = 1) {
    return cleanLines(renderQueueIndicatorString(queuedCount, marginTop));
}
function renderQueueIndicatorString(queuedCount, marginTop = 1) {
    return renderToString(_jsx(ThemeContext.Provider, { value: theme, children: _jsxs(Box, { flexDirection: "row", paddingLeft: 1, marginTop: marginTop, flexShrink: 0, children: [_jsx(Box, { width: 2, flexShrink: 0, children: _jsx(Text, { color: theme.warning, bold: true, children: "• " }) }), _jsxs(Text, { color: theme.textDim, children: [queuedCount, " message", queuedCount > 1 ? "s" : "", " queued"] })] }) }), { columns: TERMINAL_COLUMNS });
}
describe("queued message UI invariants", () => {
    it("renders queued placeholders with the same live/history row shape", () => {
        const item = queuedItem();
        const liveLines = renderLiveQueuedLines(item);
        const historyLines = renderHistoryQueuedLines(item);
        expect(liveLines).toEqual(historyLines);
        expect(liveLines[0]).toMatch(/^ • Queued: follow-up prompt/);
        expect(liveLines.join("\n")).not.toContain("↳ Queued");
        expect(liveLines.join("\n")).not.toContain("⏳");
        for (const line of liveLines) {
            expect(stringWidth(line)).toBeLessThanOrEqual(TERMINAL_COLUMNS);
        }
    });
    it("renders the active queue indicator with the same response gutter", () => {
        expect(renderQueueIndicatorLines(1)).toEqual([" • 1 message queued"]);
        expect(renderQueueIndicatorLines(2)).toEqual([" • 2 messages queued"]);
        expect(rawLines(renderQueueIndicatorString(1, 2)).slice(0, 3)).toEqual([
            "",
            "",
            " • 1 message queued",
        ]);
    });
    it("keeps queued placeholders active so insertion flush removes them from live items", () => {
        expect(isActiveItem(queuedItem())).toBe(true);
    });
    it("keeps queued lifecycle spacing stable across pending, started, and finalized states", () => {
        const renderItem = (item) => {
            if (item.kind === "queued")
                return _jsx(QueuedRow, { item: item });
            if (item.kind === "assistant")
                return _jsx(AssistantMessage, { text: item.text });
            return null;
        };
        const pendingRendered = renderToString(_jsx(ThemeContext.Provider, { value: theme, children: _jsx(TerminalSizeProvider, { children: _jsx(ChatLivePane, { liveItems: [queuedItem({ text: "queued while busy" })], renderItem: renderItem, isRunning: true, visibleStreamingText: "Still answering the current prompt.", streamingThinking: "", thinkingMs: 0, reserveStreamingSpacing: false, renderMarkdown: true, measuredLiveAreaRows: 20, assistantMarginTop: 1, streamingContinuation: false }) }) }), { columns: TERMINAL_COLUMNS });
        expect(trimTrailingEmptyLines(rawLines(pendingRendered))).toEqual([
            " • Queued: queued while busy",
            "",
            " ⏺ Still answering the current prompt.",
        ]);
        let output = "";
        const stream = {
            write(chunk) {
                output += chunk;
                return true;
            },
        };
        createTerminalHistoryPrinter({ stream }).print([
            { kind: "user", id: "user-1", text: "queued while busy" },
            queuedItem({ id: "queued-1", text: "queued while busy" }),
            { kind: "assistant", id: "assistant-1", text: "Now handling queued prompt." },
        ], context);
        const finalizedLines = trimTrailingEmptyLines(rawLines(output));
        const bottomBorderIndex = finalizedLines.findIndex((line) => line.startsWith("▀"));
        expect(bottomBorderIndex).toBeGreaterThanOrEqual(0);
        expect(finalizedLines.slice(bottomBorderIndex, bottomBorderIndex + 4)).toEqual([
            finalizedLines[bottomBorderIndex],
            " • Queued: queued while busy",
            "",
            " ⏺ Now handling queued prompt.",
        ]);
    });
    it("spaces queued rows like other agent chat rows when printed between agent items", () => {
        let output = "";
        const stream = {
            write(chunk) {
                output += chunk;
                return true;
            },
        };
        createTerminalHistoryPrinter({ stream }).print([
            { kind: "user", id: "user-1", text: "next prompt" },
            queuedItem({ id: "queued-1", text: "next prompt" }),
            { kind: "assistant", id: "assistant-2", text: "Second response." },
        ], context);
        const rendered = stripAnsi(output);
        const lines = trimTrailingEmptyLines(rawLines(rendered));
        const bottomBorderIndex = lines.findIndex((line) => line.startsWith("▀"));
        expect(bottomBorderIndex).toBeGreaterThanOrEqual(0);
        expect(lines.slice(bottomBorderIndex, bottomBorderIndex + 4)).toEqual([
            lines[bottomBorderIndex],
            " • Queued: next prompt",
            "",
            " ⏺ Second response.",
        ]);
    });
});
//# sourceMappingURL=queued-message.test.js.map