import { useEffect, useRef } from "react";
import { subscribeControllerToken } from "../input/controller";
import { ABILITY_ORDER } from "./data";
import { isRunBuffInputLocked, useGameStore } from "./store";
import { ABILITY_BY_CONTROLLER_BUTTON } from "./controllerBindings";

function cycleRunBuff(direction: 1 | -1) {
  const store = useGameStore.getState();
  if (store.draftBuffIds.length === 0) return;
  const currentIndex = store.selectedRunBuffId ? store.draftBuffIds.indexOf(store.selectedRunBuffId) : -1;
  const nextIndex = (Math.max(0, currentIndex) + direction + store.draftBuffIds.length) % store.draftBuffIds.length;
  store.setSelectedRunBuff(store.draftBuffIds[nextIndex]);
}

export function useActionBindings(enabled = true, onExit?: () => void) {
  const exitRef = useRef(onExit);
  exitRef.current = onExit;
  useEffect(() => {
    const onKeyDown = (event: KeyboardEvent) => {
      if (!enabled) return;
      if (event.repeat) return;
      const store = useGameStore.getState();
      const key = event.key.toLowerCase();
      if (store.paused) {
        if (["escape", "arrowup", "arrowdown", "enter"].includes(key)) event.preventDefault();
        if (key === "escape") store.setPaused(false);
        if (key === "arrowup") store.setPauseSelection("resume");
        if (key === "arrowdown") store.setPauseSelection("exit");
        if (key === "enter") {
          if (store.pauseSelection === "resume") store.setPaused(false);
          else exitRef.current?.();
        }
        return;
      }
      if (store.phase === "intermission") {
        if (["arrowleft", "arrowup", "arrowright", "arrowdown", "enter"].includes(key)) event.preventDefault();
        if (isRunBuffInputLocked(store)) return;
        if (key === "arrowleft" || key === "arrowup") cycleRunBuff(-1);
        if (key === "arrowright" || key === "arrowdown") cycleRunBuff(1);
        if (key === "enter") {
          if (store.selectedRunBuffId) store.chooseRunBuff(store.selectedRunBuffId);
          else store.continueRoguelikeRound();
        }
        if (key === "escape") exitRef.current?.();
        return;
      }
      if (store.phase === "victory" && store.runMode === "rogue-trials" && store.round === 5 && !store.endlessMode) {
        if (["arrowleft", "arrowup", "arrowright", "arrowdown", "enter"].includes(key)) event.preventDefault();
        if (key === "arrowleft" || key === "arrowup") store.setEndlessChoiceSelection("continue");
        if (key === "arrowright" || key === "arrowdown") store.setEndlessChoiceSelection("quit");
        if (key === "enter") {
          if (store.endlessChoiceSelection === "continue") store.startRogueTrialsEndless();
          else exitRef.current?.();
        }
        if (key === "escape") exitRef.current?.();
        return;
      }
      const numberIndex = Number(event.key) - 1;
      if (numberIndex >= 0 && numberIndex < ABILITY_ORDER.length) {
        store.castAbility(ABILITY_ORDER[numberIndex]);
        return;
      }
      switch (key) {
        case "q":
          store.cycleMember(-1);
          break;
        case "e":
          store.cycleMember(1);
          break;
        case "m":
          store.setActiveTab(store.activeTab === "map" ? "combat" : "map");
          break;
        case "i":
          store.setActiveTab(store.activeTab === "pack" ? "combat" : "pack");
          break;
        case "enter":
          if (store.phase === "briefing") store.startEncounter();
          if (store.phase === "victory" || store.phase === "defeat") store.restart();
          break;
        case "escape":
          if (store.phase === "combat") store.setPaused(true);
          else exitRef.current?.();
          break;
      }
    };
    window.addEventListener("keydown", onKeyDown);
    return () => window.removeEventListener("keydown", onKeyDown);
  }, [enabled]);

  useEffect(() => subscribeControllerToken(({ token, repeat }) => {
    if (!enabled) return;
    const store = useGameStore.getState();
    if (store.paused) {
      if (token === "Button12" || token === "Axis1-") store.setPauseSelection("resume");
      if (token === "Button13" || token === "Axis1+") store.setPauseSelection("exit");
      if (repeat) return;
      if (token === "Button1" || token === "Button9") store.setPaused(false);
      if (token === "Button0") {
        if (store.pauseSelection === "resume") store.setPaused(false);
        else exitRef.current?.();
      }
      return;
    }
    if (store.phase === "intermission") {
      if (isRunBuffInputLocked(store)) return;
      if (["Button12", "Button14", "Axis0-", "Axis1-"].includes(token)) cycleRunBuff(-1);
      if (["Button13", "Button15", "Axis0+", "Axis1+"].includes(token)) cycleRunBuff(1);
      if (!repeat && token === "Button0") {
        if (store.selectedRunBuffId) store.chooseRunBuff(store.selectedRunBuffId);
        else store.continueRoguelikeRound();
      }
      if (!repeat && token === "Button1") exitRef.current?.();
      return;
    }
    if (store.phase === "victory" && store.runMode === "rogue-trials" && store.round === 5 && !store.endlessMode) {
      if (["Button12", "Button14", "Axis0-", "Axis1-"].includes(token)) store.setEndlessChoiceSelection("continue");
      if (["Button13", "Button15", "Axis0+", "Axis1+"].includes(token)) store.setEndlessChoiceSelection("quit");
      if (!repeat && token === "Button0") {
        if (store.endlessChoiceSelection === "continue") store.startRogueTrialsEndless();
        else exitRef.current?.();
      }
      if (!repeat && token === "Button1") exitRef.current?.();
      return;
    }
    if (repeat) return;
    if (token.startsWith("Button")) {
      const ability = ABILITY_BY_CONTROLLER_BUTTON[Number(token.slice("Button".length))];
      if (ability && store.phase === "combat") store.castAbility(ability);
    }
    if (token === "Button12") store.cycleMember(-1);
    if (token === "Button13") store.cycleMember(1);
    if (token === "Button8") store.setActiveTab(store.activeTab === "map" ? "combat" : "map");
    if (token === "Button9" || (token === "Button0" && store.phase !== "combat")) {
      if (store.phase === "briefing") store.startEncounter();
      else if (store.phase === "victory" || store.phase === "defeat") store.restart();
      else if (store.phase === "combat") store.setPaused(true);
    }
  }), [enabled]);
}
