/* global React, ReactDOM, GameEngine, useTweaks, TweaksPanel, TweakSection,
   TweakSlider, TweakToggle, TweakRadio,
   HexRoyaleArena, HexRoyaleViewSize, HexRoyaleIntroOverlay, HexRoyaleResultOverlay */

const { useState, useEffect, useRef } = React;
const VIEW = HexRoyaleViewSize;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "shape": "hex",
  "yourSeat": 0,
  "aiLevel": 0.7,
  "ballStartSpeed": 280,
  "shrinkPerSec": 6,
  "paddleShrinkPerSec": 0.012,
  "ballAccelPerSec": 6,
  "ballAccelOnHit": 1.045,
  "showTrails": true,
  "showShake": true
}/*EDITMODE-END*/;

function App() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [, force] = useState(0);

  const sideCount = tweaks.shape === "hex" ? 6 : 4;
  const yourSeat = Math.min(tweaks.yourSeat, sideCount - 1);

  const gameRef = useRef(null);
  const overlayRef = useRef("intro");
  const trailRef = useRef([]);
  const arenaWrapRef = useRef(null);
  const inputRef = useRef({ paddle: 0.5 });

  useEffect(() => {
    gameRef.current = GameEngine.createGame({
      sides: sideCount,
      arenaR: 380,
      minArenaR: sideCount === 6 ? 200 : 220,
      shrinkPerSec: tweaks.shrinkPerSec,
      paddleShrinkPerSec: tweaks.paddleShrinkPerSec,
      ballStartSpeed: tweaks.ballStartSpeed,
      ballAccelPerSec: tweaks.ballAccelPerSec,
      ballAccelOnHit: tweaks.ballAccelOnHit,
      aiLevel: tweaks.aiLevel,
      yourSeat,
    });
    trailRef.current = [];
    overlayRef.current = "intro";
    inputRef.current.paddle = 0.5;
    force(x => x + 1);
  }, [sideCount, yourSeat, tweaks.shrinkPerSec, tweaks.paddleShrinkPerSec,
      tweaks.ballStartSpeed, tweaks.ballAccelPerSec, tweaks.ballAccelOnHit,
      tweaks.aiLevel]);

  useEffect(() => {
    let raf, last = performance.now();
    const loop = (now) => {
      const dt = Math.min(0.033, (now - last) / 1000);
      last = now;
      const g = gameRef.current;
      if (g && overlayRef.current === "playing") {
        GameEngine.setHumanPaddle(g, inputRef.current.paddle);
        GameEngine.step(g, dt);
        if (tweaks.showTrails) {
          trailRef.current.push({ x: g.ball.pos.x, y: g.ball.pos.y, t: now });
          if (trailRef.current.length > 22) trailRef.current.shift();
        } else if (trailRef.current.length) trailRef.current = [];
        if (g.state === "roundover" && overlayRef.current !== "roundover") {
          overlayRef.current = "roundover";
        }
      }
      force(x => (x + 1) | 0);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [tweaks.showTrails]);

  useEffect(() => {
    const node = arenaWrapRef.current;
    if (!node) return;
    const handle = (e) => {
      const g = gameRef.current; if (!g) return;
      const svg = node.querySelector("svg"); if (!svg) return;
      const rect = svg.getBoundingClientRect();
      const px = e.touches ? e.touches[0].clientX : e.clientX;
      const py = e.touches ? e.touches[0].clientY : e.clientY;
      const x = ((px - rect.left) / rect.width - 0.5) * VIEW;
      const y = ((py - rect.top) / rect.height - 0.5) * VIEW;
      const side = g.sides[g.yourSeat];
      const fromAx = x - side.a.x, fromAy = y - side.a.y;
      let t = (fromAx * side.tan.x + fromAy * side.tan.y) / side.length;
      t = Math.max(0, Math.min(1, t));
      inputRef.current.paddle = t;
    };
    node.addEventListener("mousemove", handle);
    node.addEventListener("touchmove", handle, { passive: true });
    return () => {
      node.removeEventListener("mousemove", handle);
      node.removeEventListener("touchmove", handle);
    };
  }, [sideCount, yourSeat]);

  useEffect(() => {
    const keys = {};
    const start = () => {
      const g = gameRef.current; if (!g) return;
      GameEngine.startRound(g);
      overlayRef.current = "playing";
      inputRef.current.paddle = 0.5;
      trailRef.current = [];
    };
    const down = (e) => {
      keys[e.key] = true;
      if (e.key === " " || e.key === "Enter") {
        if (overlayRef.current === "intro" || overlayRef.current === "roundover") {
          start();
          e.preventDefault();
        }
      }
    };
    const up = (e) => { keys[e.key] = false; };
    window.addEventListener("keydown", down);
    window.addEventListener("keyup", up);
    let raf;
    const tick = () => {
      const left = keys["ArrowLeft"] || keys["a"] || keys["A"];
      const right = keys["ArrowRight"] || keys["d"] || keys["D"];
      if (left || right) {
        const dir = (right ? 1 : 0) - (left ? 1 : 0);
        inputRef.current.paddle = Math.max(0, Math.min(1, inputRef.current.paddle + dir * 0.018));
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => {
      window.removeEventListener("keydown", down);
      window.removeEventListener("keyup", up);
      cancelAnimationFrame(raf);
    };
  }, []);

  const startGame = () => {
    const g = gameRef.current; if (!g) return;
    GameEngine.startRound(g);
    overlayRef.current = "playing";
    inputRef.current.paddle = 0.5;
    trailRef.current = [];
  };

  const game = gameRef.current;
  const shake = game && tweaks.showShake && game.cameraShake > 0.4;

  return React.createElement("div", { className: "stage" + (shake ? " shake" : "") },
    React.createElement(TopBar, { game, sideCount, yourSeat }),
    React.createElement("div", { className: "arena-wrap", ref: arenaWrapRef },
      React.createElement(HexRoyaleArena, {
        game,
        trail: trailRef.current,
        showTrails: tweaks.showTrails,
      }),
      overlayRef.current === "intro" && React.createElement(HexRoyaleIntroOverlay, {
        sideCount, yourSeat, onStart: startGame,
      }),
      overlayRef.current === "roundover" && React.createElement(HexRoyaleResultOverlay, {
        game, yourSeat, onRestart: startGame,
      }),
    ),
    React.createElement(BottomBar),
    React.createElement(GameTweaks, { tweaks, setTweak, sideCount }),
  );
}

function TopBar({ game, sideCount, yourSeat }) {
  const time = game ? game.time : 0;
  const speed = game ? Math.round(game.ball.speed) : 0;
  const alive = game ? game.aliveCount : sideCount;
  const arena = game ? Math.round((game.arenaR / game.opts.arenaR) * 100) : 100;
  const mins = Math.floor(time / 60);
  const secs = Math.floor(time % 60).toString().padStart(2, "0");

  return React.createElement("div", { className: "topbar" },
    React.createElement("div", { className: "brand" },
      React.createElement("div", { className: "brand-mark" },
        React.createElement("svg", { viewBox: "-12 -12 24 24" },
          React.createElement("polygon", {
            points: hexPoints(11), fill: "none", stroke: "#FDDA24", strokeWidth: 1.5,
          }),
          React.createElement("circle", { cx: 0, cy: 0, r: 3.5, fill: "#FDDA24" })
        )
      ),
      React.createElement("div", { className: "brand-name" },
        "HEX ", React.createElement("b", null, "ROYALE")
      ),
      React.createElement("span", { className: "brand-tag" },
        sideCount === 6 ? "6P · HEX" : "4P · SQUARE"
      ),
    ),
    React.createElement("div", { className: "players" },
      Array.from({ length: sideCount }).map((_, i) => {
        const p = game ? game.players[i] : null;
        const meta = GameEngine.PALETTE[i];
        return React.createElement("div", {
          key: i,
          className: "chip" + (p && !p.alive ? " out" : "") + (i === yourSeat ? " you" : ""),
        },
          React.createElement("span", {
            className: "chip-dot",
            style: { background: meta.color },
          }),
          meta.name + (i === yourSeat ? " · YOU" : "")
        );
      })
    ),
    React.createElement("div", { className: "hud-stats" },
      stat("Alive", `${alive}/${sideCount}`, alive <= 2 ? "danger" : "accent"),
      stat("Time", `${mins}:${secs}`),
      stat("Ball", `${speed}`),
      stat("Arena", `${arena}%`, arena < 60 ? "danger" : ""),
    )
  );
}
function stat(label, value, cls = "") {
  return React.createElement("div", { className: "stat", key: label },
    React.createElement("div", { className: "stat-label" }, label),
    React.createElement("div", { className: "stat-value " + cls }, value)
  );
}

function hexPoints(r) {
  const pts = [];
  for (let i = 0; i < 6; i++) {
    const a = -Math.PI / 2 + i * Math.PI / 3;
    pts.push(`${(r * Math.cos(a)).toFixed(2)},${(r * Math.sin(a)).toFixed(2)}`);
  }
  return pts.join(" ");
}

function BottomBar() {
  return React.createElement("div", { className: "bottombar" },
    React.createElement("div", null,
      "Move",
      React.createElement("span", { className: "kbd" }, "MOUSE"),
      "or",
      React.createElement("span", { className: "kbd" }, "←"),
      React.createElement("span", { className: "kbd" }, "→"),
    ),
    React.createElement("div", null,
      "Yellow paddle is yours · Miss once → you become a wall"
    ),
    React.createElement("div", null,
      "Toggle ",
      React.createElement("span", { className: "kbd" }, "Tweaks"),
      " in toolbar to remix"
    ),
  );
}

function GameTweaks({ tweaks, setTweak, sideCount }) {
  return React.createElement(TweaksPanel, null,
    React.createElement(TweakSection, { title: "Match" },
      React.createElement(TweakRadio, {
        label: "Arena shape",
        value: tweaks.shape,
        onChange: (v) => setTweak("shape", v),
        options: [
          { label: "Hex · 6P", value: "hex" },
          { label: "Square · 4P", value: "square" },
        ],
      }),
      React.createElement(TweakSlider, {
        label: "Your seat",
        min: 0, max: sideCount - 1, step: 1,
        value: Math.min(tweaks.yourSeat, sideCount - 1),
        onChange: (v) => setTweak("yourSeat", v),
      }),
      React.createElement(TweakSlider, {
        label: "AI difficulty",
        min: 0.2, max: 1.0, step: 0.05,
        value: tweaks.aiLevel,
        onChange: (v) => setTweak("aiLevel", v),
      }),
    ),
    React.createElement(TweakSection, { title: "Ball" },
      React.createElement(TweakSlider, {
        label: "Start speed",
        min: 160, max: 520, step: 20, unit: "u/s",
        value: tweaks.ballStartSpeed,
        onChange: (v) => setTweak("ballStartSpeed", v),
      }),
      React.createElement(TweakSlider, {
        label: "Ramp / sec",
        min: 0, max: 24, step: 1, unit: "u/s²",
        value: tweaks.ballAccelPerSec,
        onChange: (v) => setTweak("ballAccelPerSec", v),
      }),
      React.createElement(TweakSlider, {
        label: "Hit boost",
        min: 1.00, max: 1.10, step: 0.005, unit: "×",
        value: tweaks.ballAccelOnHit,
        onChange: (v) => setTweak("ballAccelOnHit", v),
      }),
    ),
    React.createElement(TweakSection, { title: "Closing in" },
      React.createElement(TweakSlider, {
        label: "Arena shrink",
        min: 0, max: 24, step: 1, unit: "px/s",
        value: tweaks.shrinkPerSec,
        onChange: (v) => setTweak("shrinkPerSec", v),
      }),
      React.createElement(TweakSlider, {
        label: "Paddle shrink",
        min: 0, max: 0.04, step: 0.002, unit: "/s",
        value: tweaks.paddleShrinkPerSec,
        onChange: (v) => setTweak("paddleShrinkPerSec", v),
      }),
    ),
    React.createElement(TweakSection, { title: "FX" },
      React.createElement(TweakToggle, {
        label: "Ball trail",
        value: tweaks.showTrails,
        onChange: (v) => setTweak("showTrails", v),
      }),
      React.createElement(TweakToggle, {
        label: "Screen shake",
        value: tweaks.showShake,
        onChange: (v) => setTweak("showShake", v),
      }),
    ),
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(
  React.createElement(App)
);
