import { useEffect, useRef } from 'react';
import { navigateByDirection } from '@noriginmedia/norigin-spatial-navigation';
import { useInputMode } from '../context/InputModeContext';

const BUTTON_A = 0;
const BUTTON_B = 1;
const BUTTON_DPAD_UP = 12;
const BUTTON_DPAD_DOWN = 13;
const BUTTON_DPAD_LEFT = 14;
const BUTTON_DPAD_RIGHT = 15;
const BUTTON_LB = 4;
const BUTTON_RB = 5;
const AXIS_THRESHOLD = 0.5;
const INITIAL_DELAY_MS = 400;
const REPEAT_RATE_MS = 100;

export const useGamepad = () => {
  const requestRef = useRef<number>();
  const lastState = useRef<Record<string, boolean>>({});
  const lastFireTime = useRef<Record<string, number>>({});
  const { setMode } = useInputMode();

  const handleInput = (id: string, isPressed: boolean, action: () => void, repeatable = true) => {
    const now = performance.now();
    const wasPressed = lastState.current[id];

    if (isPressed) {
      setMode('gamepad');
      if (!wasPressed) {
        // Initial press isolated
        action();
        lastFireTime.current[id] = now;
        lastState.current[id] = true;
      } else if (repeatable) {
        // Holding press calculates repeat boundaries natively
        const holdTime = now - lastFireTime.current[id];
        if (holdTime > INITIAL_DELAY_MS) {
          action();
          // Reset tracker mathematically for consecutive rapid fires
          lastFireTime.current[id] = now - INITIAL_DELAY_MS + REPEAT_RATE_MS;
        }
      }
    } else {
      if (wasPressed) {
        lastFireTime.current[id] = 0;
        lastState.current[id] = false;
      }
    }
  };

  const dispatchEnter = () => {
    const eventParams = { bubbles: true, cancelable: true };
    const keydown = new window.KeyboardEvent('keydown', eventParams);
    Object.defineProperty(keydown, 'keyCode', { get: () => 13 });
    Object.defineProperty(keydown, 'key', { get: () => 'Enter' });
    document.dispatchEvent(keydown);
    window.dispatchEvent(keydown);
  };

  const dispatchEscape = () => {
    const eventParams = { bubbles: true, cancelable: true };
    const keydown = new window.KeyboardEvent('keydown', eventParams);
    Object.defineProperty(keydown, 'keyCode', { get: () => 27 });
    Object.defineProperty(keydown, 'key', { get: () => 'Escape' });
    document.dispatchEvent(keydown);
    window.dispatchEvent(keydown);
  };

  const checkGamepad = () => {
    try {
      const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];
      
      // Multiplex all gamepads to defeat Ghost Virtual Devices hogs natively occupying slot 0
      for (let i = 0; i < gamepads.length; i++) {
        const gp = gamepads[i];
        if (!gp) continue;

        const up = gp.buttons[BUTTON_DPAD_UP]?.pressed || (gp.axes[1] !== undefined && gp.axes[1] < -AXIS_THRESHOLD);
        const down = gp.buttons[BUTTON_DPAD_DOWN]?.pressed || (gp.axes[1] !== undefined && gp.axes[1] > AXIS_THRESHOLD);
        const left = gp.buttons[BUTTON_DPAD_LEFT]?.pressed || (gp.axes[0] !== undefined && gp.axes[0] < -AXIS_THRESHOLD);
        const right = gp.buttons[BUTTON_DPAD_RIGHT]?.pressed || (gp.axes[0] !== undefined && gp.axes[0] > AXIS_THRESHOLD);
        const enter = gp.buttons[BUTTON_A]?.pressed;
        const back = gp.buttons[BUTTON_B]?.pressed;

        handleInput(`gp${i}_up`, up, () => navigateByDirection('up', {}));
        handleInput(`gp${i}_down`, down, () => navigateByDirection('down', {}));
        handleInput(`gp${i}_left`, left, () => navigateByDirection('left', {}));
        handleInput(`gp${i}_right`, right, () => navigateByDirection('right', {}));
        handleInput(`gp${i}_enter`, enter, () => dispatchEnter(), false);
        handleInput(`gp${i}_back`, back, () => dispatchEscape(), false);

        const lb = gp.buttons[BUTTON_LB]?.pressed;
        const rb = gp.buttons[BUTTON_RB]?.pressed;
        handleInput(`gp${i}_lb`, lb, () => window.dispatchEvent(new CustomEvent('previousplatform')));
        handleInput(`gp${i}_rb`, rb, () => window.dispatchEvent(new CustomEvent('nextplatform')));

        // Right analog stick — scroll the currently focused list
        const rsX = gp.axes[2] ?? 0;
        const rsY = gp.axes[3] ?? 0;
        if (Math.abs(rsX) > AXIS_THRESHOLD || Math.abs(rsY) > AXIS_THRESHOLD) {
          setMode('gamepad');
          window.dispatchEvent(new CustomEvent('analogscroll', { detail: { dx: rsX, dy: rsY } }));
        }
      }
    } catch (e) {
      console.error("Gamepad Polling Error", e);
    }

    requestRef.current = requestAnimationFrame(checkGamepad);
  };

  useEffect(() => {
    const onConnect = () => console.log("Gamepad Connected Native Callback!");
    const onDisconnect = () => console.log("Gamepad Disconnected Native Callback!");
    window.addEventListener("gamepadconnected", onConnect);
    window.addEventListener("gamepaddisconnected", onDisconnect);

    requestRef.current = requestAnimationFrame(checkGamepad);
    return () => {
      if (requestRef.current) cancelAnimationFrame(requestRef.current);
      window.removeEventListener("gamepadconnected", onConnect);
      window.removeEventListener("gamepaddisconnected", onDisconnect);
    };
  }, []);
};
