// app.jsx — Root App: state machine wiring engine + UI surfaces

const { useState, useEffect, useRef, useCallback } = React;
const { HUD, SidePanel, StartScreen, PauseOverlay, ResultOverlay, GameOverModal, FooterHints } = window.NS_UI;

// Tweaks defaults — wrapped in markers for host-side persistence
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "candy",
  "showGrain": true,
  "showFooter": true
}/*EDITMODE-END*/;

const PALETTES = {
  candy: ["#c084fc", "#67e8f9", "#fde68a", "#f9a8d4"],
  sunset: ["#fb7185", "#fbbf24", "#a78bfa", "#fde68a"],
  ocean: ["#67e8f9", "#a5b4fc", "#5eead4", "#bae6fd"],
  forest: ["#86efac", "#fde68a", "#5eead4", "#a3e635"],
};

function App() {
  const [phase, setPhase] = useState("start"); // 'start'|'playing'|'paused'|'gameover'
  const [ui, setUi] = useState({
    score: 0, round: 1, timeLeft: 0,
    collected: [], target: 5, operation: "+",
  });
  const [resultMsg, setResultMsg] = useState(null);
  const [showResultOverlay, setShowResultOverlay] = useState(false);
  const [soundOn, setSoundOn] = useState(true);
  const [totalSeconds, setTotalSeconds] = useState(180);
  const [difficulty, setDifficulty] = useState(2);
  const [tweaks, setTweak] = (window.useTweaks || (() => [TWEAK_DEFAULTS, () => {}]))(TWEAK_DEFAULTS);

  const canvasRef = useRef(null);
  const engineRef = useRef(null);
  const pendingStartRef = useRef(null); // { seconds, difficulty } to start once canvas is ready
  const soundOnRef = useRef(soundOn);
  useEffect(() => { soundOnRef.current = soundOn; }, [soundOn]);

  // Viewport-fill scaling: zoom #root so the game always fills the window
  useEffect(() => {
    const NATURAL_W = 1060;
    const NATURAL_H = 770;
    const update = () => {
      const s = Math.min(window.innerWidth / NATURAL_W, window.innerHeight / NATURAL_H);
      document.documentElement.style.setProperty('--shell-zoom', s.toFixed(4));
    };
    update();
    window.addEventListener('resize', update);
    return () => window.removeEventListener('resize', update);
  }, []);

  // Apply mesh palette via CSS vars
  useEffect(() => {
    const p = PALETTES[tweaks.palette] || PALETTES.candy;
    document.body.style.setProperty("--mesh-1", p[0]);
    document.body.style.setProperty("--mesh-2", p[1]);
    document.body.style.setProperty("--mesh-3", p[2]);
    document.body.style.setProperty("--mesh-4", p[3]);
  }, [tweaks.palette]);

  const playSound = useCallback((name) => {
    if (!soundOnRef.current) return;
    window.SoundPlayer?.play(name);
  }, []);

  // Init engine + (re)start once the canvas is in the DOM
  useEffect(() => {
    if (phase === "start" || phase === "gameover") return;
    if (!canvasRef.current) return;
    if (!engineRef.current) {
      engineRef.current = new window.SnakeEngine(canvasRef.current, {
        onUiUpdate: (next) => setUi((prev) => ({ ...prev, ...next })),
        onResult: (msg) => {
          setResultMsg(msg);
          setShowResultOverlay(true);
          setTimeout(() => setShowResultOverlay(false), 1800);
          setTimeout(() => setResultMsg(null), 2400);
        },
        onSound: playSound,
        onGameOver: () => { setPhase("gameover"); },
      });
    }
    if (pendingStartRef.current != null) {
      const { seconds: s, difficulty: d } = pendingStartRef.current;
      pendingStartRef.current = null;
      engineRef.current.start(s, d);
    }
  }, [phase, playSound]);

  const startGame = (seconds, diff) => {
    const d = diff ?? difficulty;
    setDifficulty(d);
    setTotalSeconds(seconds);
    setResultMsg(null);
    setShowResultOverlay(false);
    pendingStartRef.current = { seconds, difficulty: d };
    setPhase("playing");
    window.SoundPlayer?.resume();
    if (engineRef.current) {
      queueMicrotask(() => {
        if (pendingStartRef.current != null) {
          const { seconds: s, difficulty: dv } = pendingStartRef.current;
          pendingStartRef.current = null;
          engineRef.current.start(s, dv);
        }
      });
    }
  };

  const restartGame = () => {
    engineRef.current?.destroy();
    engineRef.current = null;
    startGame(totalSeconds, difficulty);
  };

  const quitToHome = () => {
    engineRef.current?.destroy();
    engineRef.current = null;
    setPhase("start");
    setResultMsg(null);
  };

  // Keyboard handler
  useEffect(() => {
    const onKey = (e) => {
      if (phase === "start" || phase === "gameover") return;
      const k = e.key.toLowerCase();
      let handled = true;
      if (k === "arrowup" || k === "w") engineRef.current?.setDirection(0, -1);
      else if (k === "arrowdown" || k === "s") engineRef.current?.setDirection(0, 1);
      else if (k === "arrowleft" || k === "a") engineRef.current?.setDirection(-1, 0);
      else if (k === "arrowright" || k === "d") engineRef.current?.setDirection(1, 0);
      else if (k === " " || k === "spacebar") togglePause();
      else if (k === "r") restartGame();
      else if (k === "m") setSoundOn((s) => !s);
      else if (k === "c") engineRef.current?.undoLastCollect();
      else handled = false;
      if (handled) e.preventDefault();
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [phase, totalSeconds]);

  const togglePause = () => {
    if (phase === "playing") { engineRef.current?.pause(); setPhase("paused"); }
    else if (phase === "paused") { engineRef.current?.resume(); setPhase("playing"); }
  };

  // Touch controls on canvas
  useEffect(() => {
    if (!canvasRef.current) return;
    const c = canvasRef.current;
    let startX = 0, startY = 0;
    const ts = (e) => { const t = e.touches[0]; startX = t.clientX; startY = t.clientY; };
    const te = (e) => {
      const t = e.changedTouches[0];
      const dx = t.clientX - startX, dy = t.clientY - startY;
      if (Math.hypot(dx, dy) < 30) return;
      if (Math.abs(dx) > Math.abs(dy)) engineRef.current?.setDirection(dx > 0 ? 1 : -1, 0);
      else engineRef.current?.setDirection(0, dy > 0 ? 1 : -1);
    };
    c.addEventListener("touchstart", ts, { passive: true });
    c.addEventListener("touchend", te, { passive: true });
    return () => {
      c.removeEventListener("touchstart", ts);
      c.removeEventListener("touchend", te);
    };
  }, [phase]);

  return (
    <React.Fragment>
      {tweaks.showGrain && <div className="grain" />}

      <div className="shell">
        <HUD
          difficulty={difficulty}
          operation={ui.operation}
          score={ui.score}
          round={ui.round}
          timeLeft={ui.timeLeft}
          soundEnabled={soundOn}
          onSoundToggle={() => setSoundOn(s => !s)}
          onPause={togglePause}
          paused={phase === "paused"}
        />

        <div className="game-row">
          <div className="canvas-wrap" data-screen-label="02 Canvas" style={{ position: "relative" }}>
            <canvas ref={canvasRef} />
            {phase === "paused" && (
              <PauseOverlay
                onResume={togglePause}
                onRestart={restartGame}
                onQuit={quitToHome}
              />
            )}
            {showResultOverlay && resultMsg && (
              <ResultOverlay equation={resultMsg.equation} isCorrect={resultMsg.isCorrect} />
            )}
          </div>

          <SidePanel
            collected={ui.collected}
            target={ui.target}
            operation={ui.operation}
            resultMsg={resultMsg}
            score={ui.score}
            round={ui.round}
          />
        </div>

        {tweaks.showFooter && <FooterHints phase={phase} />}
      </div>

      {phase === "start" && <StartScreen onStart={startGame} />}
      {phase === "gameover" && (
        <GameOverModal
          score={ui.score}
          round={ui.round}
          totalSeconds={totalSeconds}
          onRestart={restartGame}
          onHome={quitToHome}
        />
      )}

      {/* Tweaks */}
      <TweaksUI tweaks={tweaks} setTweak={setTweak} />
    </React.Fragment>
  );
}

function TweaksUI({ tweaks, setTweak }) {
  if (!window.TweaksPanel) return null;
  const { TweaksPanel, TweakSection, TweakRadio, TweakToggle } = window;
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="背景配色">
        <TweakRadio
          label="Mesh 主题"
          value={tweaks.palette}
          options={[
            { label: "Candy", value: "candy" },
            { label: "Sunset", value: "sunset" },
            { label: "Ocean", value: "ocean" },
            { label: "Forest", value: "forest" },
          ]}
          onChange={(v) => setTweak("palette", v)}
        />
      </TweakSection>
      <TweakSection label="质感细节">
        <TweakToggle
          label="噪点纹理"
          value={tweaks.showGrain}
          onChange={(v) => setTweak("showGrain", v)}
        />
        <TweakToggle
          label="底部快捷键栏"
          value={tweaks.showFooter}
          onChange={(v) => setTweak("showFooter", v)}
        />
      </TweakSection>
    </TweaksPanel>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
