/** Keyboard + touch input with per-frame edge detection. Listens on window so
 *  the canvas never needs focus. Touch buttons feed the same virtual keys. */

const GAME_KEYS = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Space']);

type VKey = 'left' | 'right' | 'jump' | 'attack';

export class Input {
  private held = new Set<string>();
  private pressedThisFrame = new Set<string>();
  private touchHeld = new Set<VKey>();
  private touchPressed = new Set<VKey>();
  anyKeyThisFrame = false;

  constructor() {
    window.addEventListener('keydown', (e) => {
      if (GAME_KEYS.has(e.code)) e.preventDefault(); // no page scroll
      if (e.repeat) return;
      this.held.add(e.code);
      this.pressedThisFrame.add(e.code);
      this.anyKeyThisFrame = true;
    });
    window.addEventListener('keyup', (e) => this.held.delete(e.code));
    window.addEventListener('blur', () => {
      this.held.clear();
      this.touchHeld.clear();
    });
  }

  /** wire one DOM touch button to a virtual key */
  bindButton(el: HTMLElement, key: VKey): void {
    const down = (e: Event) => {
      e.preventDefault();
      if (!this.touchHeld.has(key)) this.touchPressed.add(key);
      this.touchHeld.add(key);
      this.anyKeyThisFrame = true;
      el.classList.add('held');
    };
    const up = (e: Event) => {
      e.preventDefault();
      this.touchHeld.delete(key);
      el.classList.remove('held');
    };
    el.addEventListener('pointerdown', down);
    el.addEventListener('pointerup', up);
    el.addEventListener('pointercancel', up);
    el.addEventListener('pointerleave', up);
    el.addEventListener('contextmenu', (e) => e.preventDefault());
  }

  get left(): boolean {
    return this.held.has('ArrowLeft') || this.held.has('KeyA') || this.touchHeld.has('left');
  }
  get right(): boolean {
    return this.held.has('ArrowRight') || this.held.has('KeyD') || this.touchHeld.has('right');
  }
  get jumpHeld(): boolean {
    return (
      this.held.has('Space') || this.held.has('ArrowUp') || this.held.has('KeyW') ||
      this.touchHeld.has('jump')
    );
  }
  get jumpPressed(): boolean {
    return (
      this.pressedThisFrame.has('Space') ||
      this.pressedThisFrame.has('ArrowUp') ||
      this.pressedThisFrame.has('KeyW') ||
      this.touchPressed.has('jump')
    );
  }
  get attackPressed(): boolean {
    return (
      this.pressedThisFrame.has('KeyJ') ||
      this.pressedThisFrame.has('KeyK') ||
      this.pressedThisFrame.has('KeyX') ||
      this.touchPressed.has('attack')
    );
  }

  /** Call once at the end of each update tick. */
  endFrame(): void {
    this.pressedThisFrame.clear();
    this.touchPressed.clear();
    this.anyKeyThisFrame = false;
  }
}
