import type { KeyEvent } from "@opentui/core";
/** @jsxImportSource @opentui/react */
import { useKeyboard } from "@opentui/react";
import type { ReactNode } from "react";

import { createKeyMatcher } from "../../components/keymap.js";
import { debugInput, isCtrlCRawSequence, isEscapeRawSequence } from "./open-tui-debug.js";

const promptKeymap = createKeyMatcher({
  cancel: ["escape", "ctrl+c"],
});

export function isEscapeKeyboardEvent(event: KeyEvent): boolean {
  const keyName = event.name?.toLowerCase();
  const keyCode = event.code?.toLowerCase();
  const sequence = event.sequence ?? "";
  if (keyName === "escape" || keyName === "esc") return true;
  if (keyCode === "escape") return true;
  if (isEscapeRawSequence(sequence)) return true;
  return false;
}

export function isCtrlCKeyboardEvent(event: KeyEvent): boolean {
  const keyName = event.name?.toLowerCase();
  const sequence = event.sequence ?? "";
  if (isCtrlCRawSequence(sequence)) return true;
  if (event.ctrl && (keyName === "c" || sequence.toLowerCase() === "c")) return true;
  if (promptKeymap.match("cancel", event) && event.ctrl) return true;
  return false;
}

export function isCancelKeyboardEvent(event: KeyEvent): boolean {
  return isEscapeKeyboardEvent(event) || isCtrlCKeyboardEvent(event);
}

export function emitInterruptSignal(source: string) {
  debugInput(`interrupt source="${source}"`);
  if (process.stdout.isTTY) process.stdout.write("\n");
  process.kill(process.pid, "SIGINT");
}

export function useCancelKey(onCancel: () => void) {
  useKeyboard((event) => {
    if (!isCancelKeyboardEvent(event)) return;
    event.preventDefault?.();
    event.stopPropagation?.();
    if (isCtrlCKeyboardEvent(event)) {
      emitInterruptSignal("useCancelKey");
      return;
    }
    onCancel();
  });
}

interface PromptCancelBoundaryProps {
  onCancel: () => void;
  children: ReactNode;
}

export function PromptCancelBoundary({ onCancel, children }: PromptCancelBoundaryProps) {
  useKeyboard((event) => {
    if (!isCancelKeyboardEvent(event)) return;
    event.preventDefault?.();
    event.stopPropagation?.();
    if (isCtrlCKeyboardEvent(event)) {
      emitInterruptSignal("promptBoundary");
      return;
    }
    onCancel();
  });
  return <>{children}</>;
}
