import { useEffect, useRef, useCallback } from "react";
import { useApp } from "ink";
import { useKeypress } from "./useKeypress.js";
import { enableMouseEvents, disableMouseEvents } from "../utils/mouse.js";
import { generateMessageId } from "../utils/idGenerator.js";
const EXIT_WARNING_TIMEOUT = 3e3;
function convertKey(rawKey) {
  const key = {
    upArrow: rawKey.name === "up",
    downArrow: rawKey.name === "down",
    leftArrow: rawKey.name === "left",
    rightArrow: rawKey.name === "right",
    pageUp: rawKey.name === "pageup",
    pageDown: rawKey.name === "pagedown",
    return: rawKey.name === "return" || rawKey.name === "enter",
    escape: rawKey.name === "escape",
    ctrl: rawKey.ctrl,
    shift: rawKey.shift,
    meta: rawKey.meta,
    tab: rawKey.name === "tab",
    backspace: rawKey.name === "backspace",
    delete: rawKey.name === "delete",
    paste: rawKey.paste
  };
  let input = rawKey.sequence;
  if (rawKey.ctrl && rawKey.name && rawKey.name.length === 1) {
    input = rawKey.name;
  }
  if (rawKey.paste) {
    input = rawKey.sequence;
  }
  return { input, key };
}
function getFocusTarget(approval, activeOverlay) {
  if (approval !== null) {
    return "approval";
  }
  if (activeOverlay !== "none" && activeOverlay !== "approval") {
    return "overlay";
  }
  return "input";
}
function useInputOrchestrator({
  ui,
  approval,
  input,
  session,
  steerMessages,
  buffer,
  setUi,
  setInput,
  setMessages,
  setPendingMessages,
  setSteerMessages,
  agent,
  handlers
}) {
  const { exit } = useApp();
  const uiRef = useRef(ui);
  const approvalRef = useRef(approval);
  const inputRef = useRef(input);
  const sessionRef = useRef(session);
  const steerMessagesRef = useRef(steerMessages);
  const bufferRef = useRef(buffer);
  const handlersRef = useRef(handlers);
  useEffect(() => {
    uiRef.current = ui;
    approvalRef.current = approval;
    inputRef.current = input;
    sessionRef.current = session;
    steerMessagesRef.current = steerMessages;
    bufferRef.current = buffer;
    handlersRef.current = handlers;
  }, [ui, approval, input, session, steerMessages, buffer, handlers]);
  useEffect(() => {
    if (!ui.exitWarningShown || !ui.exitWarningTimestamp) return;
    const elapsed = Date.now() - ui.exitWarningTimestamp;
    const remaining = EXIT_WARNING_TIMEOUT - elapsed;
    if (remaining <= 0) {
      setUi((prev) => ({ ...prev, exitWarningShown: false, exitWarningTimestamp: null }));
      return;
    }
    const timer = setTimeout(() => {
      setUi((prev) => ({ ...prev, exitWarningShown: false, exitWarningTimestamp: null }));
    }, remaining);
    return () => clearTimeout(timer);
  }, [ui.exitWarningShown, ui.exitWarningTimestamp, setUi]);
  const handleCtrlC = useCallback(() => {
    const currentUi = uiRef.current;
    const currentBuffer = bufferRef.current;
    if (currentBuffer.text.length > 0) {
      currentBuffer.setText("");
      setUi((prev) => ({
        ...prev,
        exitWarningShown: true,
        exitWarningTimestamp: Date.now()
      }));
    } else {
      if (currentUi.exitWarningShown) {
        exit();
      } else {
        setUi((prev) => ({
          ...prev,
          exitWarningShown: true,
          exitWarningTimestamp: Date.now()
        }));
      }
    }
  }, [setUi, exit]);
  const handleEscape = useCallback(() => {
    const currentUi = uiRef.current;
    const currentApproval = approvalRef.current;
    const currentSession = sessionRef.current;
    const currentSteerMessages = steerMessagesRef.current;
    const currentBuffer = bufferRef.current;
    if (currentApproval !== null) {
      return false;
    }
    if (currentUi.historySearch.isActive) {
      const originalInput = currentUi.historySearch.originalInput;
      currentBuffer.setText(originalInput);
      setInput((prev) => ({ ...prev, value: originalInput }));
      setUi((prev) => ({
        ...prev,
        historySearch: {
          isActive: false,
          query: "",
          matchIndex: 0,
          originalInput: "",
          lastMatch: ""
        }
      }));
      return true;
    }
    if (currentUi.exitWarningShown) {
      setUi((prev) => ({ ...prev, exitWarningShown: false, exitWarningTimestamp: null }));
      return true;
    }
    if (currentUi.isProcessing) {
      if (currentSession.id) {
        void agent.cancel(currentSession.id).catch(() => {
        });
        void agent.clearSteerQueue(currentSession.id).catch(() => {
        });
        setSteerMessages([]);
      }
      setPendingMessages((pending) => {
        if (pending.length > 0) {
          const updated = pending.map((msg) => {
            if (msg.role === "tool" && msg.toolStatus === "running") {
              return {
                ...msg,
                toolStatus: "finished",
                toolResult: "Cancelled",
                isError: true
              };
            }
            return msg;
          });
          setMessages((prev) => [...prev, ...updated]);
        }
        return [];
      });
      setUi((prev) => ({
        ...prev,
        isCancelling: true,
        isProcessing: false,
        isThinking: false
      }));
      setMessages((prev) => [
        ...prev,
        {
          id: generateMessageId("system"),
          role: "system",
          content: "Interrupted - what should Dexto do next?",
          timestamp: /* @__PURE__ */ new Date()
        }
      ]);
      if (currentSteerMessages.length > 0) {
        const coalescedText = currentSteerMessages.map(
          (msg) => msg.content.filter(
            (part) => part.type === "text"
          ).map((part) => part.text).join("\n")
        ).filter((text) => text.length > 0).join("\n\n");
        if (coalescedText) {
          currentBuffer.setText(coalescedText);
          setInput((prev) => ({ ...prev, value: coalescedText }));
        }
        setSteerMessages([]);
      }
      return true;
    }
    if (currentUi.activeOverlay !== "none") {
      return false;
    }
    return false;
  }, [agent, setUi, setMessages, setPendingMessages, setSteerMessages, setInput]);
  const handleKeypress = useCallback(
    (rawKey) => {
      const currentUi = uiRef.current;
      const currentApproval = approvalRef.current;
      const currentHandlers = handlersRef.current;
      const { input: inputStr, key } = convertKey(rawKey);
      if (currentUi.copyModeEnabled) {
        setUi((prev) => ({ ...prev, copyModeEnabled: false }));
        enableMouseEvents();
        return;
      }
      if (currentUi.historySearch.isActive) {
        const currentInput = inputRef.current;
        const currentBuffer = bufferRef.current;
        const findMatches = (query) => {
          if (!query) return [];
          const lowerQuery = query.toLowerCase();
          return currentInput.history.filter((item) => item.toLowerCase().includes(lowerQuery)).reverse();
        };
        const applyMatchAndUpdateState = (query, matchIdx) => {
          if (!query) {
            const orig = currentUi.historySearch.originalInput;
            currentBuffer.setText(orig);
            setInput((prev) => ({ ...prev, value: orig }));
            return;
          }
          const matches = findMatches(query);
          if (matches.length > 0) {
            const idx = Math.min(matchIdx, matches.length - 1);
            const match = matches[idx];
            if (match) {
              currentBuffer.setText(match);
              setInput((prev) => ({ ...prev, value: match }));
              setUi((prev) => ({
                ...prev,
                historySearch: { ...prev.historySearch, lastMatch: match }
              }));
            }
          }
        };
        if (key.ctrl && inputStr === "e") {
          const matches = findMatches(currentUi.historySearch.query);
          if (matches.length > 0) {
            const newIdx = Math.max(0, currentUi.historySearch.matchIndex - 1);
            setUi((prev) => ({
              ...prev,
              historySearch: { ...prev.historySearch, matchIndex: newIdx }
            }));
            applyMatchAndUpdateState(currentUi.historySearch.query, newIdx);
          }
          return;
        }
        if (key.ctrl && inputStr === "r") {
          const matches = findMatches(currentUi.historySearch.query);
          if (matches.length > 0) {
            const newIdx = Math.min(
              currentUi.historySearch.matchIndex + 1,
              matches.length - 1
            );
            setUi((prev) => ({
              ...prev,
              historySearch: { ...prev.historySearch, matchIndex: newIdx }
            }));
            applyMatchAndUpdateState(currentUi.historySearch.query, newIdx);
          }
          return;
        }
        if (key.return) {
          setUi((prev) => ({
            ...prev,
            historySearch: {
              isActive: false,
              query: "",
              matchIndex: 0,
              originalInput: "",
              lastMatch: ""
            }
          }));
          return;
        }
        if (key.backspace || key.delete) {
          const newQuery = currentUi.historySearch.query.slice(0, -1);
          setUi((prev) => ({
            ...prev,
            historySearch: { ...prev.historySearch, query: newQuery, matchIndex: 0 }
          }));
          applyMatchAndUpdateState(newQuery, 0);
          return;
        }
        if (inputStr && !key.ctrl && !key.meta && !key.escape) {
          const newQuery = currentUi.historySearch.query + inputStr;
          setUi((prev) => ({
            ...prev,
            historySearch: { ...prev.historySearch, query: newQuery, matchIndex: 0 }
          }));
          applyMatchAndUpdateState(newQuery, 0);
          return;
        }
      }
      if (key.ctrl && inputStr === "r") {
        const currentBuffer = bufferRef.current;
        const currentText = currentBuffer.text;
        setUi((prev) => ({
          ...prev,
          historySearch: {
            isActive: true,
            query: "",
            matchIndex: 0,
            originalInput: currentText,
            lastMatch: ""
          }
        }));
        return;
      }
      if (key.ctrl && inputStr === "s") {
        setUi((prev) => ({ ...prev, copyModeEnabled: true }));
        disableMouseEvents();
        return;
      }
      if (key.ctrl && inputStr === "t") {
        setUi((prev) => ({ ...prev, todoExpanded: !prev.todoExpanded }));
        return;
      }
      if (key.ctrl && inputStr === "b") {
        setUi((prev) => ({
          ...prev,
          backgroundTasksExpanded: !prev.backgroundTasksExpanded
        }));
        return;
      }
      if (key.ctrl && inputStr === "c") {
        handleCtrlC();
        return;
      }
      if (key.shift && key.tab && !key.ctrl && !key.meta && currentApproval === null && currentUi.activeOverlay === "none") {
        setUi((prev) => {
          const isNormal = !prev.planModeActive && !prev.autoApproveEdits && !prev.bypassPermissions;
          if (isNormal) {
            return {
              ...prev,
              planModeActive: true,
              planModeInitialized: false,
              autoApproveEdits: false,
              bypassPermissions: false
            };
          } else if (prev.planModeActive) {
            return {
              ...prev,
              planModeActive: false,
              planModeInitialized: false,
              autoApproveEdits: true,
              bypassPermissions: false
            };
          } else if (prev.autoApproveEdits) {
            return {
              ...prev,
              autoApproveEdits: false,
              bypassPermissions: true
            };
          } else {
            return {
              ...prev,
              bypassPermissions: false
            };
          }
        });
        return;
      }
      const focusTarget = getFocusTarget(currentApproval, currentUi.activeOverlay);
      if (key.escape) {
        if (focusTarget === "approval") {
          currentHandlers.approval?.(inputStr, key);
          return;
        }
        if (handleEscape()) {
          return;
        }
      }
      switch (focusTarget) {
        case "approval":
          if (currentHandlers.approval) {
            currentHandlers.approval(inputStr, key);
          }
          break;
        case "overlay":
          if (currentHandlers.overlay) {
            currentHandlers.overlay(inputStr, key);
          }
          break;
        case "input":
          if (currentUi.exitWarningShown && !key.ctrl && !key.meta && !key.escape && inputStr.length > 0) {
            setUi((prev) => ({
              ...prev,
              exitWarningShown: false,
              exitWarningTimestamp: null
            }));
          }
          break;
      }
    },
    [handleCtrlC, handleEscape, setUi]
  );
  useKeypress(handleKeypress, { isActive: true });
}
function createApprovalInputHandler({
  onApprove,
  onDeny,
  onCancel,
  selectedOption,
  setSelectedOption,
  isCommandApproval
}) {
  return (_input, key) => {
    if (key.upArrow) {
      if (selectedOption === "yes") {
        setSelectedOption("no");
      } else if (selectedOption === "yes-session") {
        setSelectedOption("yes");
      } else {
        setSelectedOption(isCommandApproval ? "yes" : "yes-session");
      }
      return true;
    }
    if (key.downArrow) {
      if (selectedOption === "yes") {
        setSelectedOption(isCommandApproval ? "no" : "yes-session");
      } else if (selectedOption === "yes-session") {
        setSelectedOption("no");
      } else {
        setSelectedOption("yes");
      }
      return true;
    }
    if (key.return) {
      if (selectedOption === "yes") {
        onApprove(false);
      } else if (selectedOption === "yes-session") {
        onApprove(true);
      } else {
        onDeny();
      }
      return true;
    }
    if (key.escape) {
      onCancel();
      return true;
    }
    return false;
  };
}
function createSelectorInputHandler({
  itemsLength,
  selectedIndexRef,
  onSelectIndex,
  onSelect,
  onClose
}) {
  return (_input, key) => {
    if (itemsLength === 0) return false;
    if (key.upArrow) {
      const currentIndex = selectedIndexRef.current ?? 0;
      const nextIndex = (currentIndex - 1 + itemsLength) % itemsLength;
      onSelectIndex(nextIndex);
      return true;
    }
    if (key.downArrow) {
      const currentIndex = selectedIndexRef.current ?? 0;
      const nextIndex = (currentIndex + 1) % itemsLength;
      onSelectIndex(nextIndex);
      return true;
    }
    if (key.escape) {
      onClose();
      return true;
    }
    if (key.return) {
      onSelect();
      return true;
    }
    return false;
  };
}
function createAutocompleteInputHandler({
  itemsLength,
  selectedIndexRef,
  onSelectIndex,
  onSelect,
  onClose,
  onTab
}) {
  const baseHandler = createSelectorInputHandler({
    itemsLength,
    selectedIndexRef,
    onSelectIndex,
    onSelect,
    onClose
  });
  return (input, key) => {
    if (key.tab && onTab) {
      onTab();
      return true;
    }
    return baseHandler(input, key);
  };
}
function createMainInputHandler({
  value,
  cursorPos,
  onChange,
  setCursorPos,
  onSubmit,
  isDisabled,
  history,
  historyIndex,
  onHistoryNavigate,
  getLineInfo,
  getLineStart
}) {
  return (input, key) => {
    if (isDisabled) return false;
    const lines = value.split("\n");
    const isMultiLine = lines.length > 1;
    const { lineIndex, colIndex } = getLineInfo(cursorPos);
    const isCtrlJ = input === "\n";
    const isShiftEnter = input === "\\\r" || key.return && key.shift || input === "\x1B[13;2u" || input === "\x1BOM";
    const wantsNewline = isCtrlJ || isShiftEnter || key.return && key.meta;
    if (wantsNewline) {
      const newValue = value.slice(0, cursorPos) + "\n" + value.slice(cursorPos);
      onChange(newValue);
      setCursorPos(cursorPos + 1);
      return true;
    }
    if (key.return) {
      if (value.trim()) {
        onSubmit(value);
      }
      return true;
    }
    const isBackspace = key.backspace || input === "\x7F" || input === "\b";
    if (isBackspace) {
      if (cursorPos > 0) {
        const newValue = value.slice(0, cursorPos - 1) + value.slice(cursorPos);
        onChange(newValue);
        setCursorPos(cursorPos - 1);
      }
      return true;
    }
    if (key.delete) {
      if (cursorPos < value.length) {
        const newValue = value.slice(0, cursorPos) + value.slice(cursorPos + 1);
        onChange(newValue);
      }
      return true;
    }
    if (key.leftArrow) {
      setCursorPos(Math.max(0, cursorPos - 1));
      return true;
    }
    if (key.rightArrow) {
      setCursorPos(Math.min(value.length, cursorPos + 1));
      return true;
    }
    if (key.upArrow) {
      if (isMultiLine && lineIndex > 0) {
        const prevLineStart = getLineStart(lineIndex - 1);
        const prevLineLength = lines[lineIndex - 1].length;
        const newCol = Math.min(colIndex, prevLineLength);
        setCursorPos(prevLineStart + newCol);
      } else if (onHistoryNavigate && history.length > 0) {
        onHistoryNavigate("up");
      }
      return true;
    }
    if (key.downArrow) {
      if (isMultiLine && lineIndex < lines.length - 1) {
        const nextLineStart = getLineStart(lineIndex + 1);
        const nextLineLength = lines[lineIndex + 1].length;
        const newCol = Math.min(colIndex, nextLineLength);
        setCursorPos(nextLineStart + newCol);
      } else if (onHistoryNavigate && historyIndex >= 0) {
        onHistoryNavigate("down");
      }
      return true;
    }
    if (key.ctrl && input === "a") {
      setCursorPos(getLineStart(lineIndex));
      return true;
    }
    if (key.ctrl && input === "e") {
      const lineStart = getLineStart(lineIndex);
      setCursorPos(lineStart + lines[lineIndex].length);
      return true;
    }
    if (key.ctrl && input === "k") {
      const lineStart = getLineStart(lineIndex);
      const lineEnd = lineStart + lines[lineIndex].length;
      if (cursorPos < lineEnd) {
        onChange(value.slice(0, cursorPos) + value.slice(lineEnd));
      } else if (cursorPos < value.length) {
        onChange(value.slice(0, cursorPos) + value.slice(cursorPos + 1));
      }
      return true;
    }
    if (key.ctrl && input === "u") {
      const lineStart = getLineStart(lineIndex);
      if (cursorPos > lineStart) {
        onChange(value.slice(0, lineStart) + value.slice(cursorPos));
        setCursorPos(lineStart);
      }
      return true;
    }
    if (key.ctrl && input === "w") {
      if (cursorPos > 0) {
        let wordStart = cursorPos - 1;
        while (wordStart > 0 && value[wordStart] === " ") wordStart--;
        while (wordStart > 0 && value[wordStart - 1] !== " " && value[wordStart - 1] !== "\n") {
          wordStart--;
        }
        onChange(value.slice(0, wordStart) + value.slice(cursorPos));
        setCursorPos(wordStart);
      }
      return true;
    }
    if (input && !key.ctrl && !key.meta) {
      const newValue = value.slice(0, cursorPos) + input + value.slice(cursorPos);
      onChange(newValue);
      setCursorPos(cursorPos + input.length);
      return true;
    }
    return false;
  };
}
export {
  createApprovalInputHandler,
  createAutocompleteInputHandler,
  createMainInputHandler,
  createSelectorInputHandler,
  useInputOrchestrator
};
