/** Keyboard (WASD/arrows + space + 1-4) and touch (virtual joystick + action button). */

export interface InputCallbacks {
  onAction: () => void;
  onTool: (index: number) => void;
  onAnyGesture: () => void; // unlock audio
}

const keys = new Set<string>();
let joyVec = { x: 0, y: 0 };
let joyPointer: number | null = null;

export function initInput(cb: InputCallbacks): void {
  window.addEventListener('keydown', (e) => {
    cb.onAnyGesture();
    const k = e.key.toLowerCase();
    if (['arrowup', 'arrowdown', 'arrowleft', 'arrowright', ' '].includes(k)) e.preventDefault();
    if (e.repeat) return;
    keys.add(k);
    if (k === ' ' || k === 'enter') cb.onAction();
    if (k >= '1' && k <= '4') cb.onTool(Number(k) - 1);
  });
  window.addEventListener('keyup', (e) => keys.delete(e.key.toLowerCase()));
  window.addEventListener('blur', () => keys.clear());

  // ---- virtual joystick ----
  const zone = document.getElementById('joy-zone')!;
  const base = document.getElementById('joy-base')!;
  const nub = document.getElementById('joy-nub')!;
  const R = 44;

  const setNub = (dx: number, dy: number) => {
    nub.style.transform = `translate(${dx}px, ${dy}px)`;
  };

  zone.addEventListener('pointerdown', (e) => {
    cb.onAnyGesture();
    joyPointer = e.pointerId;
    zone.setPointerCapture(e.pointerId);
    const zr = zone.getBoundingClientRect();
    base.style.left = `${e.clientX - zr.left}px`;
    base.style.top = `${e.clientY - zr.top}px`;
    base.classList.add('active');
    setNub(0, 0);
  });
  zone.addEventListener('pointermove', (e) => {
    if (e.pointerId !== joyPointer) return;
    const br = base.getBoundingClientRect();
    let dx = e.clientX - (br.left + br.width / 2);
    let dy = e.clientY - (br.top + br.height / 2);
    const len = Math.hypot(dx, dy);
    if (len > R) {
      dx = (dx / len) * R;
      dy = (dy / len) * R;
    }
    setNub(dx, dy);
    const dead = 0.18;
    const nx = dx / R, ny = dy / R;
    joyVec = {
      x: Math.abs(nx) < dead ? 0 : nx,
      y: Math.abs(ny) < dead ? 0 : ny,
    };
  });
  const joyEnd = (e: PointerEvent) => {
    if (e.pointerId !== joyPointer) return;
    joyPointer = null;
    joyVec = { x: 0, y: 0 };
    base.classList.remove('active');
    setNub(0, 0);
  };
  zone.addEventListener('pointerup', joyEnd);
  zone.addEventListener('pointercancel', joyEnd);

  // ---- action button ----
  const action = document.getElementById('action-btn')!;
  action.addEventListener('pointerdown', (e) => {
    e.preventDefault();
    cb.onAnyGesture();
    cb.onAction();
  });

  // unlock audio on any pointer press too
  window.addEventListener('pointerdown', () => cb.onAnyGesture(), { passive: true });
}

/** combined movement vector, components in [-1, 1] */
export function moveVector(): { x: number; y: number } {
  let x = 0, y = 0;
  if (keys.has('arrowleft') || keys.has('a')) x -= 1;
  if (keys.has('arrowright') || keys.has('d')) x += 1;
  if (keys.has('arrowup') || keys.has('w')) y -= 1;
  if (keys.has('arrowdown') || keys.has('s')) y += 1;
  x += joyVec.x;
  y += joyVec.y;
  return { x: Math.max(-1, Math.min(1, x)), y: Math.max(-1, Math.min(1, y)) };
}
