/** Keyboard input with per-frame edge detection. Listens on window so the
 *  canvas never needs focus. */
const GAME_KEYS = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Space']);

export class Input {
  private held = new Set<string>();
  private pressedThisFrame = new Set<string>();
  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());
  }

  get left(): boolean {
    return this.held.has('ArrowLeft') || this.held.has('KeyA');
  }
  get right(): boolean {
    return this.held.has('ArrowRight') || this.held.has('KeyD');
  }
  get jumpHeld(): boolean {
    return this.held.has('Space') || this.held.has('ArrowUp') || this.held.has('KeyW');
  }
  get jumpPressed(): boolean {
    return (
      this.pressedThisFrame.has('Space') ||
      this.pressedThisFrame.has('ArrowUp') ||
      this.pressedThisFrame.has('KeyW')
    );
  }
  get leftPressed(): boolean {
    return this.pressedThisFrame.has('ArrowLeft') || this.pressedThisFrame.has('KeyA');
  }
  get rightPressed(): boolean {
    return this.pressedThisFrame.has('ArrowRight') || this.pressedThisFrame.has('KeyD');
  }
  get dashPressed(): boolean {
    return (
      this.pressedThisFrame.has('ShiftLeft') ||
      this.pressedThisFrame.has('ShiftRight') ||
      this.pressedThisFrame.has('KeyX') ||
      this.pressedThisFrame.has('KeyK')
    );
  }

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