import type { Keybinding } from "../../types";
import type { RendererContext } from "../context";

export function createKeyboardHandlers(
  ctx: RendererContext,
  options: {
    handleRuntimeOptionsKeydown: (e: KeyboardEvent) => boolean;
    handleSubsyncKeydown: (e: KeyboardEvent) => boolean;
    handleKikuKeydown: (e: KeyboardEvent) => boolean;
    handleJimakuKeydown: (e: KeyboardEvent) => boolean;
    saveInvisiblePositionEdit: () => void;
    cancelInvisiblePositionEdit: () => void;
    setInvisiblePositionEditMode: (enabled: boolean) => void;
    applyInvisibleSubtitleOffsetPosition: () => void;
    updateInvisiblePositionEditHud: () => void;
  },
) {
  const CHORD_MAP = new Map<string, { type: "mpv" | "electron"; command?: string[]; action?: () => void }>([
    ["KeyS", { type: "mpv", command: ["script-message", "subminer-start"] }],
    ["Shift+KeyS", { type: "mpv", command: ["script-message", "subminer-stop"] }],
    ["KeyT", { type: "mpv", command: ["script-message", "subminer-toggle"] }],
    ["KeyI", { type: "mpv", command: ["script-message", "subminer-toggle-invisible"] }],
    ["Shift+KeyI", { type: "mpv", command: ["script-message", "subminer-show-invisible"] }],
    ["KeyU", { type: "mpv", command: ["script-message", "subminer-hide-invisible"] }],
    ["KeyO", { type: "mpv", command: ["script-message", "subminer-options"] }],
    ["KeyR", { type: "mpv", command: ["script-message", "subminer-restart"] }],
    ["KeyC", { type: "mpv", command: ["script-message", "subminer-status"] }],
    ["KeyY", { type: "mpv", command: ["script-message", "subminer-menu"] }],
    [
      "KeyD",
      { type: "electron", action: () => window.electronAPI.toggleDevTools() },
    ],
  ]);

  function isInteractiveTarget(target: EventTarget | null): boolean {
    if (!(target instanceof Element)) return false;
    if (target.closest(".modal")) return true;
    if (ctx.dom.subtitleContainer.contains(target)) return true;
    if (target.tagName === "IFRAME" && target.id?.startsWith("yomitan-popup")) {
      return true;
    }
    if (target.closest && target.closest('iframe[id^="yomitan-popup"]')) return true;
    return false;
  }

  function keyEventToString(e: KeyboardEvent): string {
    const parts: string[] = [];
    if (e.ctrlKey) parts.push("Ctrl");
    if (e.altKey) parts.push("Alt");
    if (e.shiftKey) parts.push("Shift");
    if (e.metaKey) parts.push("Meta");
    parts.push(e.code);
    return parts.join("+");
  }

  function isInvisiblePositionToggleShortcut(e: KeyboardEvent): boolean {
    return (
      e.code === ctx.platform.invisiblePositionEditToggleCode &&
      !e.altKey &&
      e.shiftKey &&
      (e.ctrlKey || e.metaKey)
    );
  }

  function handleInvisiblePositionEditKeydown(e: KeyboardEvent): boolean {
    if (!ctx.platform.isInvisibleLayer) return false;

    if (isInvisiblePositionToggleShortcut(e)) {
      e.preventDefault();
      if (ctx.state.invisiblePositionEditMode) {
        options.cancelInvisiblePositionEdit();
      } else {
        options.setInvisiblePositionEditMode(true);
      }
      return true;
    }

    if (!ctx.state.invisiblePositionEditMode) return false;

    const step = e.shiftKey
      ? ctx.platform.invisiblePositionStepFastPx
      : ctx.platform.invisiblePositionStepPx;

    if (e.key === "Escape") {
      e.preventDefault();
      options.cancelInvisiblePositionEdit();
      return true;
    }

    if (e.key === "Enter" || ((e.ctrlKey || e.metaKey) && e.code === "KeyS")) {
      e.preventDefault();
      options.saveInvisiblePositionEdit();
      return true;
    }

    if (
      e.key === "ArrowUp" ||
      e.key === "ArrowDown" ||
      e.key === "ArrowLeft" ||
      e.key === "ArrowRight" ||
      e.key === "h" ||
      e.key === "j" ||
      e.key === "k" ||
      e.key === "l" ||
      e.key === "H" ||
      e.key === "J" ||
      e.key === "K" ||
      e.key === "L"
    ) {
      e.preventDefault();
      if (e.key === "ArrowUp" || e.key === "k" || e.key === "K") {
        ctx.state.invisibleSubtitleOffsetYPx += step;
      } else if (e.key === "ArrowDown" || e.key === "j" || e.key === "J") {
        ctx.state.invisibleSubtitleOffsetYPx -= step;
      } else if (e.key === "ArrowLeft" || e.key === "h" || e.key === "H") {
        ctx.state.invisibleSubtitleOffsetXPx -= step;
      } else if (e.key === "ArrowRight" || e.key === "l" || e.key === "L") {
        ctx.state.invisibleSubtitleOffsetXPx += step;
      }
      options.applyInvisibleSubtitleOffsetPosition();
      options.updateInvisiblePositionEditHud();
      return true;
    }

    return true;
  }

  function resetChord(): void {
    ctx.state.chordPending = false;
    if (ctx.state.chordTimeout !== null) {
      clearTimeout(ctx.state.chordTimeout);
      ctx.state.chordTimeout = null;
    }
  }

  async function setupMpvInputForwarding(): Promise<void> {
    const keybindings: Keybinding[] = await window.electronAPI.getKeybindings();
    ctx.state.keybindingsMap = new Map();
    for (const binding of keybindings) {
      if (binding.command) {
        ctx.state.keybindingsMap.set(binding.key, binding.command);
      }
    }

    document.addEventListener("keydown", (e: KeyboardEvent) => {
      const yomitanPopup = document.querySelector('iframe[id^="yomitan-popup"]');
      if (yomitanPopup) return;
      if (handleInvisiblePositionEditKeydown(e)) return;

      if (ctx.state.runtimeOptionsModalOpen) {
        options.handleRuntimeOptionsKeydown(e);
        return;
      }
      if (ctx.state.subsyncModalOpen) {
        options.handleSubsyncKeydown(e);
        return;
      }
      if (ctx.state.kikuModalOpen) {
        options.handleKikuKeydown(e);
        return;
      }
      if (ctx.state.jimakuModalOpen) {
        options.handleJimakuKeydown(e);
        return;
      }

      if (ctx.state.chordPending) {
        const modifierKeys = [
          "ShiftLeft",
          "ShiftRight",
          "ControlLeft",
          "ControlRight",
          "AltLeft",
          "AltRight",
          "MetaLeft",
          "MetaRight",
        ];
        if (modifierKeys.includes(e.code)) {
          return;
        }

        e.preventDefault();
        const secondKey = keyEventToString(e);
        const action = CHORD_MAP.get(secondKey);
        resetChord();
        if (action) {
          if (action.type === "mpv" && action.command) {
            window.electronAPI.sendMpvCommand(action.command);
          } else if (action.type === "electron" && action.action) {
            action.action();
          }
        }
        return;
      }

      if (
        e.code === "KeyY" &&
        !e.ctrlKey &&
        !e.altKey &&
        !e.shiftKey &&
        !e.metaKey &&
        !e.repeat
      ) {
        e.preventDefault();
        ctx.state.chordPending = true;
        ctx.state.chordTimeout = setTimeout(() => {
          resetChord();
        }, 1000);
        return;
      }

      const keyString = keyEventToString(e);
      const command = ctx.state.keybindingsMap.get(keyString);

      if (command) {
        e.preventDefault();
        window.electronAPI.sendMpvCommand(command);
      }
    });

    document.addEventListener("mousedown", (e: MouseEvent) => {
      if (e.button === 2 && !isInteractiveTarget(e.target)) {
        e.preventDefault();
        window.electronAPI.sendMpvCommand(["cycle", "pause"]);
      }
    });

    document.addEventListener("contextmenu", (e: Event) => {
      if (!isInteractiveTarget(e.target)) {
        e.preventDefault();
      }
    });
  }

  return {
    setupMpvInputForwarding,
  };
}
