import { jsx, jsxs } from "react/jsx-runtime";
import { useCallback, useRef, useEffect } from "react";
import { Box, Text, useStdout } from "ink";
import { useKeypress } from "../hooks/useKeypress.js";
import { readClipboardImage } from "../utils/clipboardUtils.js";
const PASTE_COLLAPSE_LINE_THRESHOLD = 3;
const PASTE_COLLAPSE_CHAR_THRESHOLD = 150;
const isMac = process.platform === "darwin";
const KEY_LABELS = {
  ctrlT: isMac ? "\u2303T" : "Ctrl+T",
  altUp: isMac ? "\u2325\u2191" : "Alt+Up",
  altDown: isMac ? "\u2325\u2193" : "Alt+Down"
};
function isBackspaceKey(key) {
  return key.name === "backspace" || key.sequence === "\x7F" || key.sequence === "\b";
}
function isForwardDeleteKey(key) {
  return key.name === "delete";
}
function HighlightedText({ text, query }) {
  if (!query || !text) {
    return /* @__PURE__ */ jsx(Text, { children: text });
  }
  const lowerText = text.toLowerCase();
  const lowerQuery = query.toLowerCase();
  const matchIndex = lowerText.indexOf(lowerQuery);
  if (matchIndex === -1) {
    return /* @__PURE__ */ jsx(Text, { children: text });
  }
  const before = text.slice(0, matchIndex);
  const match = text.slice(matchIndex, matchIndex + query.length);
  const after = text.slice(matchIndex + query.length);
  return /* @__PURE__ */ jsxs(Text, { children: [
    before,
    /* @__PURE__ */ jsx(Text, { color: "green", bold: true, children: match }),
    after
  ] });
}
function TextBufferInput({
  buffer,
  onSubmit,
  onQueueSubmit,
  placeholder,
  isDisabled = false,
  onHistoryNavigate,
  onCurrentTurnEdit,
  onTriggerOverlay,
  maxViewportLines = 10,
  isActive,
  onKeyboardScroll,
  imageCount = 0,
  onImagePaste,
  images = [],
  onImageRemove,
  pastedBlocks = [],
  onPasteBlock,
  onPasteBlockUpdate,
  onPasteBlockRemove,
  highlightQuery,
  onCycleReasoningVariant
}) {
  const { stdout } = useStdout();
  const terminalWidth = stdout?.columns || 80;
  const imageCountRef = useRef(imageCount);
  useEffect(() => {
    imageCountRef.current = imageCount;
  }, [imageCount]);
  const pasteCounterRef = useRef(pastedBlocks.length);
  useEffect(() => {
    pasteCounterRef.current = Math.max(pasteCounterRef.current, pastedBlocks.length);
  }, [pastedBlocks.length]);
  const checkRemovedImages = useCallback(() => {
    if (!onImageRemove || images.length === 0) return;
    const currentText = buffer.text;
    for (const img of images) {
      if (!currentText.includes(img.placeholder)) {
        onImageRemove(img.id);
      }
    }
  }, [buffer, images, onImageRemove]);
  const checkRemovedPasteBlocks = useCallback(() => {
    if (!onPasteBlockRemove || pastedBlocks.length === 0) return;
    const currentText = buffer.text;
    for (const block of pastedBlocks) {
      const textToFind = block.isCollapsed ? block.placeholder : block.fullText;
      if (!currentText.includes(textToFind)) {
        onPasteBlockRemove(block.id);
      }
    }
  }, [buffer, pastedBlocks, onPasteBlockRemove]);
  const findExpandedBlock = useCallback(() => {
    return pastedBlocks.find((block) => !block.isCollapsed) || null;
  }, [pastedBlocks]);
  const findCollapsedBlockAtCursor = useCallback(() => {
    if (pastedBlocks.length === 0) return null;
    const currentText = buffer.text;
    const [cursorRow, cursorCol] = buffer.cursor;
    const cursorOffset = getCursorPosition(buffer.lines, cursorRow, cursorCol);
    for (const block of pastedBlocks) {
      if (!block.isCollapsed) continue;
      const startIdx = currentText.indexOf(block.placeholder);
      if (startIdx === -1) continue;
      const endIdx = startIdx + block.placeholder.length;
      if (cursorOffset >= startIdx && cursorOffset <= endIdx) {
        return block;
      }
    }
    return null;
  }, [buffer, pastedBlocks]);
  const handlePasteToggle = useCallback(() => {
    if (!onPasteBlockUpdate) return;
    const expandedBlock = findExpandedBlock();
    const currentText = buffer.text;
    if (expandedBlock) {
      const normalizedCurrent = currentText.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
      const normalizedFullText = expandedBlock.fullText.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
      const startIdx = normalizedCurrent.indexOf(normalizedFullText);
      if (startIdx === -1) {
        onPasteBlockUpdate(expandedBlock.id, { isCollapsed: true });
        return;
      }
      const before = currentText.slice(0, startIdx);
      const after = currentText.slice(startIdx + normalizedFullText.length);
      const newText = before + expandedBlock.placeholder + after;
      const [cursorRow, cursorCol] = buffer.cursor;
      const cursorOffset = getCursorPosition(buffer.lines, cursorRow, cursorCol);
      let newCursorOffset = cursorOffset;
      if (cursorOffset > startIdx) {
        const lengthDiff = expandedBlock.placeholder.length - normalizedFullText.length;
        newCursorOffset = Math.max(startIdx, cursorOffset + lengthDiff);
      }
      buffer.setText(newText);
      buffer.moveToOffset(Math.min(newCursorOffset, newText.length));
      onPasteBlockUpdate(expandedBlock.id, { isCollapsed: true });
      return;
    }
    const collapsedBlock = findCollapsedBlockAtCursor();
    if (collapsedBlock) {
      const startIdx = currentText.indexOf(collapsedBlock.placeholder);
      if (startIdx === -1) return;
      const before = currentText.slice(0, startIdx);
      const after = currentText.slice(startIdx + collapsedBlock.placeholder.length);
      const newText = before + collapsedBlock.fullText + after;
      buffer.setText(newText);
      buffer.moveToOffset(startIdx);
      onPasteBlockUpdate(collapsedBlock.id, { isCollapsed: false });
    }
  }, [buffer, findExpandedBlock, findCollapsedBlockAtCursor, onPasteBlockUpdate]);
  const handleKeypress = useCallback(
    (key) => {
      if (isDisabled) return;
      if (key.name === "tab" && !key.shift && !key.ctrl && !key.meta && onCycleReasoningVariant) {
        onCycleReasoningVariant();
        return;
      }
      const currentText = buffer.text;
      const cursorVisualRow2 = buffer.visualCursor[0];
      const visualLines2 = buffer.allVisualLines;
      if (onKeyboardScroll) {
        if (key.name === "pageup" || key.shift && key.name === "up") {
          onKeyboardScroll("up");
          return;
        }
        if (key.name === "pagedown" || key.shift && key.name === "down") {
          onKeyboardScroll("down");
          return;
        }
      }
      if (key.ctrl && key.name === "v" && onImagePaste) {
        void (async () => {
          try {
            const clipboardImage = await readClipboardImage();
            if (clipboardImage) {
              const currentCount = imageCountRef.current;
              const imageNumber = currentCount + 1;
              imageCountRef.current = imageNumber;
              const placeholder2 = `[Image ${imageNumber}]`;
              const pendingImage = {
                id: `img-${Date.now()}-${imageNumber}`,
                data: clipboardImage.data,
                mimeType: clipboardImage.mimeType,
                placeholder: placeholder2
              };
              onImagePaste(pendingImage);
              buffer.insert(placeholder2);
            }
          } catch {
          }
        })();
        return;
      }
      if (key.name === "return" && key.meta && !key.paste && onQueueSubmit) {
        if (currentText.trim()) {
          onQueueSubmit(currentText);
        }
        return;
      }
      const isCtrlJ = key.sequence === "\n";
      const isShiftEnter = key.sequence === "\\\r" || key.name === "return" && key.shift || key.sequence === "\x1B[13;2u" || key.sequence === "\x1BOM";
      const isPasteReturn = key.name === "return" && key.paste;
      const wantsNewline = isCtrlJ || isShiftEnter || isPasteReturn;
      if (wantsNewline) {
        buffer.newline();
        return;
      }
      if (key.name === "return" && !key.paste) {
        if (currentText.trim()) {
          onSubmit(currentText);
        }
        return;
      }
      if (key.ctrl && key.name === "z" && !key.shift) {
        buffer.undo();
        return;
      }
      if (key.ctrl && key.name === "y" || key.ctrl && key.shift && key.name === "z") {
        buffer.redo();
        return;
      }
      if (key.ctrl && key.name === "t") {
        handlePasteToggle();
        return;
      }
      if (isBackspaceKey(key) && !key.meta) {
        const prevText = buffer.text;
        const [cursorRow, cursorCol] = buffer.cursor;
        const cursorPos = getCursorPosition(buffer.lines, cursorRow, cursorCol);
        buffer.backspace();
        checkRemovedImages();
        checkRemovedPasteBlocks();
        if (onTriggerOverlay && cursorPos > 0) {
          const deletedChar = prevText[cursorPos - 1];
          const expectedNewText = prevText.slice(0, cursorPos - 1) + prevText.slice(cursorPos);
          if (deletedChar === "/" && cursorPos === 1) {
            onTriggerOverlay("close");
          } else if (deletedChar === "@") {
            const hasValidAt = /(^|[\s])@/.test(expectedNewText);
            if (!hasValidAt) {
              onTriggerOverlay("close");
            }
          }
        }
        return;
      }
      if (isForwardDeleteKey(key)) {
        buffer.del();
        checkRemovedImages();
        checkRemovedPasteBlocks();
        return;
      }
      if (key.ctrl && key.name === "w") {
        buffer.deleteWordLeft();
        checkRemovedImages();
        checkRemovedPasteBlocks();
        return;
      }
      if (key.meta && isBackspaceKey(key)) {
        buffer.deleteWordLeft();
        checkRemovedImages();
        checkRemovedPasteBlocks();
        return;
      }
      if (key.name === "left") {
        buffer.move(key.meta || key.ctrl ? "wordLeft" : "left");
        return;
      }
      if (key.name === "right") {
        buffer.move(key.meta || key.ctrl ? "wordRight" : "right");
        return;
      }
      if (key.meta && key.name === "up") {
        if (onCurrentTurnEdit?.()) {
          return;
        }
        buffer.moveToOffset(0);
        return;
      }
      if (key.meta && key.name === "down") {
        buffer.moveToOffset(currentText.length);
        return;
      }
      if (key.name === "up") {
        if (cursorVisualRow2 === 0 && onHistoryNavigate) {
          onHistoryNavigate("up");
        } else {
          buffer.move("up");
        }
        return;
      }
      if (key.name === "down") {
        if (cursorVisualRow2 >= visualLines2.length - 1 && onHistoryNavigate) {
          onHistoryNavigate("down");
        } else {
          buffer.move("down");
        }
        return;
      }
      if (key.ctrl && key.name === "a") {
        buffer.move("home");
        return;
      }
      if (key.ctrl && key.name === "e") {
        buffer.move("end");
        return;
      }
      if (key.ctrl && key.name === "k") {
        buffer.killLineRight();
        checkRemovedImages();
        checkRemovedPasteBlocks();
        return;
      }
      if (key.ctrl && key.name === "u") {
        buffer.killLineLeft();
        checkRemovedImages();
        checkRemovedPasteBlocks();
        return;
      }
      if (key.meta && key.name === "b") {
        buffer.move("wordLeft");
        return;
      }
      if (key.meta && key.name === "f") {
        buffer.move("wordRight");
        return;
      }
      if (key.insertable && !key.ctrl && !key.meta) {
        const [cursorRow, cursorCol] = buffer.cursor;
        const cursorPos = getCursorPosition(buffer.lines, cursorRow, cursorCol);
        if (key.paste && onPasteBlock) {
          const pastedText = key.sequence.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
          const lineCount = (pastedText.match(/\n/g)?.length ?? 0) + 1;
          if (lineCount >= PASTE_COLLAPSE_LINE_THRESHOLD || pastedText.length > PASTE_COLLAPSE_CHAR_THRESHOLD) {
            pasteCounterRef.current += 1;
            const pasteNumber = pasteCounterRef.current;
            const placeholder2 = `[Paste ${pasteNumber}: ~${lineCount} lines]`;
            const pasteBlock = {
              id: `paste-${Date.now()}-${pasteNumber}`,
              number: pasteNumber,
              fullText: pastedText,
              lineCount,
              isCollapsed: true,
              placeholder: placeholder2
            };
            buffer.insert(placeholder2);
            onPasteBlock(pasteBlock);
            return;
          }
        }
        buffer.insert(key.sequence, { paste: key.paste });
        if (onTriggerOverlay) {
          if (key.sequence === "/" && cursorPos === 0) {
            onTriggerOverlay("slash-autocomplete");
          } else if (key.sequence === "@") {
            onTriggerOverlay("resource-autocomplete");
          } else if (/\s/.test(key.sequence)) {
            onTriggerOverlay("close");
          }
        }
      }
    },
    [
      buffer,
      isDisabled,
      onSubmit,
      onQueueSubmit,
      onHistoryNavigate,
      onCurrentTurnEdit,
      onTriggerOverlay,
      onKeyboardScroll,
      // imageCount intentionally omitted - callback uses imageCountRef which is synced via useEffect
      onImagePaste,
      checkRemovedImages,
      checkRemovedPasteBlocks,
      handlePasteToggle,
      onPasteBlock
    ]
  );
  useKeypress(handleKeypress, { isActive: isActive && !isDisabled });
  const bufferText = buffer.text;
  const visualCursor = buffer.visualCursor;
  const visualLines = buffer.allVisualLines;
  const cursorVisualRow = visualCursor[0];
  const cursorVisualCol = visualCursor[1];
  const separator = "\u2500".repeat(terminalWidth);
  const totalLines = visualLines.length;
  const isShellMode = bufferText.startsWith("!");
  const promptPrefix = isShellMode ? "$ " : "> ";
  const promptColor = isShellMode ? "yellow" : "green";
  const separatorColor = isShellMode ? "yellow" : "gray";
  let startLine = 0;
  let endLine = totalLines;
  if (totalLines > maxViewportLines) {
    const halfViewport = Math.floor(maxViewportLines / 2);
    startLine = Math.max(0, cursorVisualRow - halfViewport);
    endLine = Math.min(totalLines, startLine + maxViewportLines);
    if (endLine === totalLines) {
      startLine = Math.max(0, totalLines - maxViewportLines);
    }
  }
  const visibleLines = visualLines.slice(startLine, endLine);
  if (bufferText === "") {
    return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: terminalWidth, children: [
      /* @__PURE__ */ jsx(Text, { color: "gray", children: separator }),
      /* @__PURE__ */ jsxs(Box, { width: terminalWidth, children: [
        /* @__PURE__ */ jsx(Text, { color: "green", bold: true, children: "> " }),
        /* @__PURE__ */ jsx(Text, { inverse: true, children: " " }),
        placeholder && /* @__PURE__ */ jsx(Text, { color: "gray", children: placeholder }),
        /* @__PURE__ */ jsx(Text, { children: " ".repeat(Math.max(0, terminalWidth - 3 - (placeholder?.length || 0))) })
      ] }),
      /* @__PURE__ */ jsx(Text, { color: "gray", children: separator })
    ] });
  }
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: terminalWidth, children: [
    /* @__PURE__ */ jsx(Text, { color: separatorColor, children: separator }),
    startLine > 0 && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
      "  ",
      "\u2191 ",
      startLine,
      " more line",
      startLine > 1 ? "s" : "",
      " above (",
      KEY_LABELS.altUp,
      " to jump)"
    ] }),
    visibleLines.map((line, idx) => {
      const absoluteRow = startLine + idx;
      const isFirst = absoluteRow === 0;
      const prefix = isFirst ? promptPrefix : "  ";
      const isCursorLine = absoluteRow === cursorVisualRow;
      if (!isCursorLine) {
        return /* @__PURE__ */ jsxs(Box, { width: terminalWidth, children: [
          /* @__PURE__ */ jsx(Text, { color: promptColor, bold: isFirst, children: prefix }),
          /* @__PURE__ */ jsx(HighlightedText, { text: line, query: highlightQuery }),
          /* @__PURE__ */ jsx(Text, { children: " ".repeat(
            Math.max(0, terminalWidth - prefix.length - line.length)
          ) })
        ] }, absoluteRow);
      }
      const before = line.slice(0, cursorVisualCol);
      const atCursor = line.charAt(cursorVisualCol) || " ";
      const after = line.slice(cursorVisualCol + 1);
      return /* @__PURE__ */ jsxs(Box, { width: terminalWidth, children: [
        /* @__PURE__ */ jsx(Text, { color: promptColor, bold: isFirst, children: prefix }),
        /* @__PURE__ */ jsx(HighlightedText, { text: before, query: highlightQuery }),
        /* @__PURE__ */ jsx(Text, { inverse: true, children: atCursor }),
        /* @__PURE__ */ jsx(HighlightedText, { text: after, query: highlightQuery }),
        /* @__PURE__ */ jsx(Text, { children: " ".repeat(
          Math.max(
            0,
            terminalWidth - prefix.length - before.length - 1 - after.length
          )
        ) })
      ] }, absoluteRow);
    }),
    endLine < totalLines && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
      "  ",
      "\u2193 ",
      totalLines - endLine,
      " more line",
      totalLines - endLine > 1 ? "s" : "",
      " ",
      "below (",
      KEY_LABELS.altDown,
      " to jump)"
    ] }),
    pastedBlocks.length > 0 && /* @__PURE__ */ jsx(
      PasteBlockHint,
      {
        pastedBlocks,
        expandedBlock: findExpandedBlock(),
        cursorOnCollapsed: findCollapsedBlockAtCursor()
      }
    ),
    /* @__PURE__ */ jsx(Text, { color: separatorColor, children: separator })
  ] });
}
function PasteBlockHint({
  pastedBlocks,
  expandedBlock,
  cursorOnCollapsed
}) {
  const collapsedCount = pastedBlocks.filter((b) => b.isCollapsed).length;
  if (expandedBlock) {
    return /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
      "  ",
      KEY_LABELS.ctrlT,
      " to collapse expanded paste"
    ] });
  }
  if (cursorOnCollapsed) {
    return /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
      "  ",
      KEY_LABELS.ctrlT,
      " to expand paste"
    ] });
  }
  if (collapsedCount > 0) {
    return /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
      "  ",
      collapsedCount,
      " collapsed paste",
      collapsedCount > 1 ? "s" : "",
      " (",
      KEY_LABELS.ctrlT,
      " ",
      "on placeholder to expand)"
    ] });
  }
  return null;
}
function getCursorPosition(lines, cursorRow, cursorCol) {
  let pos = 0;
  for (let i = 0; i < cursorRow; i++) {
    pos += (lines[i]?.length ?? 0) + 1;
  }
  return pos + cursorCol;
}
export {
  TextBufferInput
};
