import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
 * ============================================================
 *  src/ui/InputBox.tsx —— 用户输入框（v0.4 多行粘贴支持版）
 * ------------------------------------------------------------
 *  v0.4 新增功能：
 *    - 多行粘贴支持：粘贴多行代码时完整保留所有行
 *    - 多行编辑模式：Enter 提交，Alt+Enter（Mac: Option+Enter）插入换行
 *    - 粘贴检测：自动识别长输入为粘贴操作
 *    - 跨平台兼容：Win / Mac / Linux
 *
 *  v0.3 修复内容：
 *    - 移除过激进的全局防抖机制（导致 Backspace 完全失效）
 *    - 改为仅对 Delete 键做去重（解决 Windows 双事件问题）
 *    - 修复 BufferView 组件重建导致的不可见问题
 *    - 保留强制刷新但精准控制时机
 * ============================================================
 */
import React, { useRef, useState, useCallback } from 'react';
import { Box, Text, useApp, useInput } from 'ink';
import { useTextBuffer } from './hooks/useTextBuffer.js';
import { usePasteHandler } from './hooks/usePasteHandler.js';
import { useInputHistory } from './hooks/useInputHistory.js';
function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
    const buf = useTextBuffer();
    const hist = useInputHistory();
    const ctrlCCountRef = useRef(0);
    const ctrlCTimerRef = useRef(null);
    const { exit } = useApp();
    // 刷新触发器：值本身不读，只用 setter 触发 InputBoxImpl 重渲（→ BufferView 随父重渲）。
    const [, setRefreshCounter] = useState(0);
    // ✅ Ctrl+R 反向搜索模式（null 表示不在搜索）
    const [searchMode, setSearchMode] = useState(null);
    // ✅ Delete 专用去重：只防止 Windows 双事件，不影响其他键
    const lastDeleteTime = useRef(0);
    const DELETE_DEBOUNCE_MS = 20; // 仅 Delete 键用极短防抖
    const forceRefresh = useCallback(() => {
        setRefreshCounter((c) => c + 1);
    }, []);
    // ✅ 粘贴处理 Hook：支持多行粘贴
    // v0.3 设计：Enter 始终发送, Alt+Enter（Mac: Option+Enter）换行, 粘贴期间拦截 Enter
    const { handleInput: handlePasteInput } = usePasteHandler({
        onPasteComplete: (text) => {
            buf.insert(text);
            forceRefresh();
        },
        multiline: true,
    });
    useInput((input, key) => {
        // ---- ✅ 粘贴检测（必须优先处理）----
        // 这会在粘贴期间忽略 Enter 键，防止多行内容被截断
        const pasteResult = handlePasteInput(input, key);
        if (pasteResult === 'paste') {
            // 粘贴内容已由 usePasteHandler 处理并插入
            return;
        }
        if (pasteResult === 'enter-in-paste') {
            // 粘贴期间的 Enter 键被忽略（不插入换行，不提交）
            return;
        }
        if (pasteResult === 'enter-newline') {
            // Alt+Enter：插入换行符（多行编辑用）
            buf.insert('\n');
            forceRefresh();
            return;
        }
        // pasteResult === 'continue'，继续普通处理
        // ---- ✅ Ctrl+R 反向搜索模式（独占按键流）----
        if (searchMode !== null) {
            // ESC 退出搜索
            if (key.escape) {
                setSearchMode(null);
                return;
            }
            // Enter 选中并提交
            if (key.return) {
                if (searchMode.hit !== null) {
                    const text = searchMode.hit;
                    setSearchMode(null);
                    buf.clear();
                    forceRefresh();
                    hist.push(text);
                    hist.resetCursor();
                    onSubmit(text);
                }
                else {
                    setSearchMode(null);
                }
                return;
            }
            // Backspace 削 query；query 削空了退出
            if (key.backspace || key.delete) {
                const nextQuery = searchMode.query.slice(0, -1);
                if (nextQuery.length === 0) {
                    setSearchMode(null);
                    return;
                }
                const nextHit = hist.search(nextQuery)[0] ?? null;
                setSearchMode({ query: nextQuery, hit: nextHit });
                return;
            }
            // Ctrl+C 退出搜索（不退出程序）
            if (key.ctrl && input === 'c') {
                setSearchMode(null);
                return;
            }
            // 字面字符（排除控制键）追加到 query
            if (input && !key.ctrl && !key.meta && !key.return && !key.escape) {
                const nextQuery = searchMode.query + input;
                const nextHit = hist.search(nextQuery)[0] ?? null;
                setSearchMode({ query: nextQuery, hit: nextHit });
                return;
            }
            // 其他按键在搜索模式下静默吞掉
            return;
        }
        // ---- ESC ----
        if (key.escape) {
            if (disabled)
                onAbort();
            return;
        }
        // ---- ✅ Ctrl+R 进入反向搜索（仅在空 buf + 非 disabled）----
        if (key.ctrl && input === 'r') {
            if (!disabled && buf.state.text.length === 0) {
                setSearchMode({ query: '', hit: null });
            }
            return;
        }
        // ---- Ctrl+C ----
        if (key.ctrl && input === 'c') {
            if (buf.state.text.length > 0) {
                buf.clear();
                forceRefresh();
                return;
            }
            if (disabled) {
                onAbort();
                return;
            }
            ctrlCCountRef.current++;
            if (ctrlCCountRef.current >= 2)
                exit();
            if (ctrlCTimerRef.current)
                clearTimeout(ctrlCTimerRef.current);
            ctrlCTimerRef.current = setTimeout(() => { ctrlCCountRef.current = 0; }, 1000);
            return;
        }
        // ---- ✅ Enter 提交（始终发送）----
        // usePasteHandler v0.3 逻辑：
        //   - Enter（单独按）：返回 'continue' → 这里执行**发送**
        //   - Alt+Enter（Mac: Option+Enter）：返回 'enter-newline' → 上面已处理为**插入换行**
        //   - Ctrl+Enter：返回 'continue' → 这里也执行**强制发送**
        //   - 粘贴期间 + Enter：返回 'enter-in-paste' → **忽略**（防误发）
        if (key.return) {
            const text = buf.state.text.trim();
            if (text.length === 0)
                return;
            // 入历史（所有非空提交都记，包括 slash 命令；连续重复 hist 内部去重）
            hist.push(text);
            hist.resetCursor();
            if (text === '/exit' || text === '/quit')
                exit();
            else if (text === '/new' || text === '/clear') {
                buf.clear();
                forceRefresh();
                onClear();
            }
            else if (text === '/compact') {
                buf.clear();
                forceRefresh();
                onCompact();
            }
            else {
                buf.clear();
                forceRefresh();
                onSubmit(text);
            }
            return;
        }
        // ---- 移动光标（无防抖，响应优先）----
        if (key.leftArrow) {
            if (key.ctrl || key.meta)
                buf.moveWordLeft();
            else
                buf.moveLeft();
            forceRefresh();
            return;
        }
        if (key.rightArrow) {
            if (key.ctrl || key.meta)
                buf.moveWordRight();
            else
                buf.moveRight();
            forceRefresh();
            return;
        }
        if (key.upArrow) {
            // 首行按 ↑ → 翻历史；中间行 → 正常移动光标
            if (buf.layout.cursorRow === 0) {
                const prev = hist.prev();
                if (prev !== null) {
                    buf.setText(prev);
                    forceRefresh();
                }
                return;
            }
            buf.moveUp();
            forceRefresh();
            return;
        }
        if (key.downArrow) {
            // 末行按 ↓ → 翻历史；中间行 → 正常移动光标
            const lastRow = buf.layout.lines.length - 1;
            if (buf.layout.cursorRow >= lastRow) {
                const nxt = hist.next();
                // next 返 null 表示走到 "新输入" 位 → 清空缓冲
                buf.setText(nxt ?? '');
                forceRefresh();
                return;
            }
            buf.moveDown();
            forceRefresh();
            return;
        }
        // ---- ✅ Backspace（无防抖，保证每次按键都生效）----
        if (key.backspace) {
            buf.deleteBefore();
            forceRefresh();
            return;
        }
        // ---- ✅ Delete（仅此键有防抖，解决 Windows 双事件）----
        if (key.delete) {
            const now = Date.now();
            if (now - lastDeleteTime.current < DELETE_DEBOUNCE_MS) {
                return; // 忽略过快的重复 Delete（Windows 特有问题）
            }
            lastDeleteTime.current = now;
            // Windows 下 key.delete 通常对应 Backspace，保持与原始行为一致
            buf.deleteBefore();
            forceRefresh();
            return;
        }
        // ---- Emacs 控制键（无防抖）----
        if (key.ctrl && !key.meta) {
            switch (input) {
                case 'a':
                    buf.moveLineStart();
                    break;
                case 'e':
                    buf.moveLineEnd();
                    break;
                case 'b':
                    buf.moveLeft();
                    break;
                case 'f':
                    buf.moveRight();
                    break;
                case 'u':
                    buf.killToLineStart();
                    break;
                case 'k':
                    buf.killToLineEnd();
                    break;
                case 'w':
                    buf.deleteWordBefore();
                    break;
                case 'h':
                    buf.deleteBefore();
                    break; // Ctrl+H = Backspace
                default: return; // 忽略其他控制键
            }
            forceRefresh();
            return;
        }
        // ---- Alt 快捷键 ----
        if (key.meta && input === '<') {
            buf.moveBufferStart();
            forceRefresh();
            return;
        }
        if (key.meta && input === '>') {
            buf.moveBufferEnd();
            forceRefresh();
            return;
        }
        // ---- ✅ 字符输入（已排除粘贴，已排除裸 Enter）----
        // Alt+Enter 在多数终端发 \x1b\r：Ink 把 \x1b 剥掉后 input='\r'、key.return=false、
        // key.meta=false，从这里落地。把 \r/\r\n 统一成 \n，textBuffer 才能真切分逻辑行
        // （否则 layout 永远 1 行 → ↑/↓ 失效、输入框不长高，光标只能左右）。
        if (input && !key.meta) {
            const normalized = input.replace(/\r\n?/g, '\n');
            buf.insert(normalized);
            forceRefresh();
        }
    });
    // ✅ 搜索模式下覆盖整个 BufferView，显示 (reverse-i-search)`<query>': <hit>
    if (searchMode !== null) {
        return _jsx(ReverseSearchView, { query: searchMode.query, hit: searchMode.hit });
    }
    // BufferView 非 memo：InputBoxImpl 因按键 setState（useTextBuffer 的 buf state
    // 或 refreshCounter 任一变化）重渲时，BufferView 作为子组件随之重渲、重读 buf.layout。
    // 故无需把刷新计数透传给它（透传是冗余的）。
    return _jsx(BufferView, { buf: buf, disabled: disabled });
}
/**
 * v2.x 修复：用 React.memo 包装 InputBox。
 *
 * 根因：App.tsx 之前用 deps=[chat] 包 handleClear / handleSubmit；chat 每次
 * useChat 重渲都是新对象引用（流式期 reasoningPreview/streamingText 每 100ms flush，
 * ~10 Hz）→ handleClear / handleSubmit 引用频繁变 → InputBox 收到新 onClear / onSubmit
 * → 不 memo 时强制重渲 → Ink 收到 InputBox 子树输出变化 → 整个 live 区被重写 →
 * 看起来 spinner 每帧打新行。
 *
 * App.tsx deps 已改为精细字段（chat.clearHistory / chat.submit 等），引用稳定；
 * 配合此处 React.memo，InputBox 在 onSubmit / onAbort / onClear / onCompact /
 * disabled 真正变化时才重渲。
 */
export const InputBox = React.memo(InputBoxImpl);
// ---------- 反向搜索视图 ----------
function ReverseSearchView({ query, hit, }) {
    // hit 可能含换行；仅展示首行避免撑爆 InputBox
    const hitFirstLine = hit !== null ? hit.split('\n', 1)[0] : null;
    const hitDisplay = hitFirstLine === null
        ? '<no match>'
        : hit !== null && hit.includes('\n')
            ? `${hitFirstLine} …`
            : hitFirstLine;
    return (_jsxs(Box, { borderStyle: "round", borderColor: "magenta", paddingX: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: "magenta", bold: true, children: '(reverse-i-search)`' }), _jsx(Text, { color: "yellow", children: query }), _jsx(Text, { color: "magenta", bold: true, children: "': " }), _jsx(Text, { color: hitFirstLine === null ? 'gray' : 'white', children: hitDisplay })] }), _jsx(Box, { children: _jsx(Text, { color: "gray", dimColor: true, children: "Enter \u63D0\u4EA4 \u00B7 ESC \u53D6\u6D88 \u00B7 Backspace \u5220\u5B57\u7B26" }) })] }));
}
function BufferView({ buf, disabled }) {
    // buf.layout 由 useTextBuffer 的 useMemo([state]) 维护：父组件每次重渲传入的 buf
    // 都已带最新 layout，这里直接读即可（BufferView 故意不 memo，随父重渲）。
    const { lines, cursorRow, cursorCol } = buf.layout;
    const promptColor = disabled ? 'gray' : 'cyan';
    const prompt = disabled ? '⏳ ' : '> ';
    return (_jsx(Box, { borderStyle: "round", borderColor: promptColor, paddingX: 1, flexDirection: "column", children: lines.map((line, row) => {
            const isFirst = row === 0;
            const isCursorRow = row === cursorRow && !disabled;
            // key 只用 row：保持稳定，避免逐行重建（layout 变化由父级重渲带下来）
            return (_jsxs(Box, { children: [_jsx(Text, { color: promptColor, bold: true, children: isFirst ? prompt : '  ' }), isCursorRow ? _jsx(CursorLine, { line: line, col: cursorCol }) : _jsx(Text, { children: line || ' ' })] }, row));
        }) }));
}
/** 光标行渲染（稳定，不会被重建） */
function CursorLine({ line, col }) {
    const cps = Array.from(line);
    const before = cps.slice(0, col).join('');
    const cursorChar = cps[col] ?? ' ';
    const after = cps.slice(col + 1).join('');
    return (_jsxs(Text, { children: [before, _jsx(Text, { inverse: true, children: cursorChar }), after] }));
}
