/* ============================================================
   input.js — keyboard state + per-fighter command buffer
   Detects motion inputs (quarter-circle, etc.) for specials.
   ============================================================ */

const Keys = {};
window.addEventListener("keydown", (e) => {
  // stop arrows/space from scrolling the page
  if (["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"," "].includes(e.key)) e.preventDefault();
  Keys[e.code] = true;
  Sound.resume();
});
window.addEventListener("keyup", (e) => { Keys[e.code] = false; });

// A control scheme maps semantic buttons -> physical keys.
const SCHEMES = {
  p1: {
    left: "KeyA", right: "KeyD", up: "KeyW", down: "KeyS",
    punch: "KeyF", kick: "KeyG", block: "KeyH",
  },
  p2: {
    left: "ArrowLeft", right: "ArrowRight", up: "ArrowUp", down: "ArrowDown",
    punch: "KeyK", kick: "KeyL", block: "Semicolon",
  },
};

/* InputState wraps one scheme: tracks held buttons, edge-triggered
   presses, and a directional history buffer for motion commands. */
class InputState {
  constructor(scheme) {
    this.scheme = scheme;
    this.held = {};
    this.pressedEdge = {};   // true only on the frame the key went down
    this.prev = {};
    this.dirBuffer = [];     // {dir:'down'|'fwd'|'back'|'neutral'|'downfwd'..., t}
    this.bufferWindow = 380; // ms window to complete a motion
  }

  // facing: +1 = fighter faces right, -1 = faces left. Used to map fwd/back.
  update(facing, now) {
    const s = this.scheme;
    const read = (k) => !!Keys[s[k]];

    const cur = {
      left: read("left"), right: read("right"),
      up: read("up"), down: read("down"),
      punch: read("punch"), kick: read("kick"), block: read("block"),
    };
    // edge detection
    for (const k in cur) this.pressedEdge[k] = cur[k] && !this.prev[k];
    this.prev = { ...cur };
    this.held = cur;

    // build directional token relative to facing
    let h = 0;
    if (cur.left) h -= 1;
    if (cur.right) h += 1;
    let token = "neutral";
    const fwd = facing; // pressing toward opponent
    if (cur.down && h === fwd) token = "downfwd";
    else if (cur.down && h === -fwd) token = "downback";
    else if (cur.down) token = "down";
    else if (h === fwd) token = "fwd";
    else if (h === -fwd) token = "back";

    const last = this.dirBuffer[this.dirBuffer.length - 1];
    if (!last || last.dir !== token) this.dirBuffer.push({ dir: token, t: now });
    // trim old
    while (this.dirBuffer.length && now - this.dirBuffer[0].t > this.bufferWindow + 200)
      this.dirBuffer.shift();
  }

  down(btn) { return !!this.held[btn]; }
  pressed(btn) { return !!this.pressedEdge[btn]; }

  // Did a sequence of directions occur recently, ending now-ish?
  // seq e.g. ['down','downfwd','fwd']  (quarter circle forward)
  motion(seq, now) {
    let idx = 0;
    for (let i = 0; i < this.dirBuffer.length; i++) {
      const d = this.dirBuffer[i];
      if (now - d.t > this.bufferWindow) continue;
      if (d.dir === seq[idx]) {
        idx++;
        if (idx === seq.length) return true;
      }
    }
    // allow loose match: also accept if it contains the key transitions
    return false;
  }

  consumeMotion() { this.dirBuffer = []; }
}
