// app.jsx — main App, game logic, race track
const { useState: useStateA, useEffect: useEffectA, useRef: useRefA, useMemo: useMemoA, useCallback: useCallbackA } = React;

// ───────────────────────────────────────────────────────────
// Question generator (sums within 10 for kindergarten)
// ───────────────────────────────────────────────────────────
function genQuestion(maxSum) {
  const ms = maxSum || 10;
  const answer = Math.floor(Math.random() * (ms + 1));      // 0..ms
  const a = Math.floor(Math.random() * (answer + 1));        // 0..answer
  const b = answer - a;
  // options
  const set = new Set([answer]);
  while (set.size < 4) {
    let cand = Math.floor(Math.random() * (ms + 1));
    // tend to keep options reasonably close to answer
    if (Math.random() < 0.5) {
      cand = Math.max(0, Math.min(ms, answer + (Math.floor(Math.random() * 5) - 2)));
    }
    set.add(cand);
  }
  const options = [...set];
  // shuffle
  for (let i = options.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [options[i], options[j]] = [options[j], options[i]];
  }
  return { a, b, answer, options };
}

function genPowerUps(raceLength) {
  const ups = [];
  for (let lane = 0; lane < 2; lane++) {
    const count = Math.max(2, Math.floor(raceLength / 4));
    const positions = new Set();
    let attempts = 0;
    while (positions.size < count && attempts < 50) {
      attempts++;
      const p = 2 + Math.floor(Math.random() * (raceLength - 3));
      // avoid clustering
      let ok = true;
      for (const existing of positions) {
        if (Math.abs(existing - p) < 2) { ok = false; break; }
      }
      if (ok) positions.add(p);
    }
    [...positions].forEach((pos) => {
      const r = Math.random();
      const type = r < 0.65 ? 'star' : 'rocket';
      ups.push({ id: lane + '-' + pos, lane, position: pos, type, collected: false });
    });
  }
  return ups;
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "maxSum": 10,
  "raceLength": 10,
  "powerUpsEnabled": true,
  "soundOn": true
}/*EDITMODE-END*/;

// ───────────────────────────────────────────────────────────
// Main App
// ───────────────────────────────────────────────────────────
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  const [screen, setScreen] = useStateA('setup'); // setup | countdown | playing | gameover
  const [players, setPlayers] = useStateA(null);
  const [question, setQuestion] = useStateA(null);
  const [positions, setPositions] = useStateA([0, 0]);
  const [scores, setScores] = useStateA([0, 0]);
  const [powerUps, setPowerUps] = useStateA([]);
  const [winner, setWinner] = useStateA(null);
  const [questionsAsked, setQuestionsAsked] = useStateA(0);
  const [bestRecords, setBestRecords] = useStateA([]);
  const [feedback, setFeedback] = useStateA({}); // {p1: 'wrong'|'correct'|null, p2: ...}
  const [bonusPops, setBonusPops] = useStateA([]); // floating "+1", "+2" popups
  const [boostingLane, setBoostingLane] = useStateA(null); // briefly mark a lane as boosting
  const lockRef = useRefA(false); // lock during transition between questions

  // Sound state mirrored
  useEffectA(() => { GameAudio.setEnabled(t.soundOn); }, [t.soundOn]);

  // Load records
  useEffectA(() => {
    try {
      const saved = JSON.parse(localStorage.getItem('addRaceBest') || '[]');
      setBestRecords(saved);
    } catch (e) {}
  }, []);

  const saveRecord = (winnerPlayer, qs, len) => {
    try {
      const saved = JSON.parse(localStorage.getItem('addRaceBest') || '[]');
      saved.push({
        name: winnerPlayer.name,
        avatar: winnerPlayer.avatar,
        questions: qs,
        length: len,
        date: Date.now(),
      });
      // sort: fewest questions to win, capped at 20
      saved.sort((a, b) => (a.questions / a.length) - (b.questions / b.length));
      const trimmed = saved.slice(0, 20);
      localStorage.setItem('addRaceBest', JSON.stringify(trimmed));
      setBestRecords(trimmed);
    } catch (e) {}
  };

  const startGame = ({ players: ps }) => {
    setPlayers(ps);
    setPositions([0, 0]);
    setScores([0, 0]);
    setPowerUps(t.powerUpsEnabled ? genPowerUps(t.raceLength) : []);
    setWinner(null);
    setQuestionsAsked(0);
    setQuestion(genQuestion(t.maxSum));
    setFeedback({});
    setBonusPops([]);
    setScreen('countdown');
  };

  const onCountdownDone = () => setScreen('playing');

  const playAgain = () => {
    if (!players) return;
    startGame({ players });
  };
  const backToSetup = () => {
    setScreen('setup');
  };

  // Compute advance + power-up collection
  const advance = (lane, baseMove) => {
    setPositions((prev) => {
      let pos = prev[lane];
      let target = pos + baseMove;
      const collected = [];
      let safety = 10;
      let totalBonus = 0;

      // pick up power-ups iteratively
      const collectIn = (from, to) => {
        const newOnes = powerUps.filter(p =>
          p.lane === lane && !p.collected && !collected.find(c => c.id === p.id) &&
          p.position > from && p.position <= to
        );
        return newOnes;
      };

      while (safety-- > 0) {
        const newOnes = collectIn(pos, target);
        if (newOnes.length === 0) break;
        let bonus = 0;
        newOnes.forEach(p => {
          collected.push(p);
          bonus += (p.type === 'star') ? 1 : 2;
        });
        totalBonus += bonus;
        pos = target;
        target = pos + bonus;
      }

      if (collected.length > 0) {
        // mark them collected
        setPowerUps((prevPU) => prevPU.map(p =>
          collected.find(c => c.id === p.id) ? { ...p, collected: true } : p
        ));
        // play collect sound
        collected.forEach((c, i) => {
          setTimeout(() => GameAudio.play(c.type === 'rocket' ? 'boost' : 'collect'), i * 120);
        });
        // bonus popup
        const totalMove = baseMove + totalBonus;
        setBonusPops((bp) => [...bp, {
          id: Math.random().toString(36).slice(2),
          lane, amount: totalMove,
          ts: Date.now()
        }]);
      } else {
        // simple +1 popup
        setBonusPops((bp) => [...bp, {
          id: Math.random().toString(36).slice(2),
          lane, amount: baseMove,
          ts: Date.now()
        }]);
      }

      const finalPos = Math.min(t.raceLength, target);
      const out = [...prev];
      out[lane] = finalPos;
      return out;
    });
  };

  const onAnswer = (lane, value) => {
    if (lockRef.current) return;
    if (!question) return;
    if (value === question.answer) {
      lockRef.current = true;
      GameAudio.play('correct');
      setFeedback({ [lane]: 'correct' });
      setBoostingLane(lane);
      setScores((s) => { const o = [...s]; o[lane] += 1; return o; });
      setQuestionsAsked((q) => q + 1);

      advance(lane, 1);

      setTimeout(() => setBoostingLane(null), 400);

      // After animation, check winner / next question
      setTimeout(() => {
        setPositions((cur) => {
          const newPositions = cur;
          if (newPositions[lane] >= t.raceLength) {
            setWinner(lane);
            setScreen('gameover');
            // save record using the latest counts
            setQuestionsAsked((qa) => {
              setPlayers((pp) => {
                if (pp) saveRecord(pp[lane], qa, t.raceLength);
                return pp;
              });
              return qa;
            });
          } else {
            setQuestion(genQuestion(t.maxSum));
            setFeedback({});
          }
          lockRef.current = false;
          return newPositions;
        });
      }, 900);
    } else {
      GameAudio.play('wrong');
      setFeedback((f) => ({ ...f, [lane]: { wrong: value } }));
      setTimeout(() => {
        setFeedback((f) => {
          const o = { ...f };
          if (o[lane] && o[lane].wrong === value) delete o[lane];
          return o;
        });
      }, 1000);
    }
  };

  // Clean up old bonus pops
  useEffectA(() => {
    if (bonusPops.length === 0) return;
    const t1 = setTimeout(() => {
      setBonusPops((bp) => bp.filter(b => Date.now() - b.ts < 1100));
    }, 1100);
    return () => clearTimeout(t1);
  }, [bonusPops]);

  return (
    <div className="app">
      <SkyDecor />

      {screen === 'setup' && (
        <SetupScreen
          onStart={startGame}
          raceLength={t.raceLength}
          setRaceLength={(v) => setTweak('raceLength', v)}
          soundOn={t.soundOn}
          toggleSound={() => setTweak('soundOn', !t.soundOn)}
          bestRecords={bestRecords}
        />
      )}

      {screen !== 'setup' && players && (
        <GameScreen
          players={players}
          question={question}
          positions={positions}
          scores={scores}
          powerUps={powerUps}
          raceLength={t.raceLength}
          feedback={feedback}
          bonusPops={bonusPops}
          boostingLane={boostingLane}
          onAnswer={onAnswer}
          soundOn={t.soundOn}
          toggleSound={() => setTweak('soundOn', !t.soundOn)}
          locked={lockRef.current}
        />
      )}

      {screen === 'countdown' && (
        <Countdown onDone={onCountdownDone} />
      )}

      {screen === 'gameover' && winner !== null && players && (
        <GameOver
          winner={winner}
          players={players.map((p, i) => ({ ...p, score: scores[i] }))}
          questionsAsked={questionsAsked}
          raceLength={t.raceLength}
          onPlayAgain={playAgain}
          onBackToSetup={backToSetup}
        />
      )}

      <TweaksPanel title="设置">
        <TweakSection label="题目难度" />
        <TweakRadio
          label="加法范围"
          value={t.maxSum}
          options={[
            { value: 5,  label: '5以内' },
            { value: 10, label: '10以内' },
            { value: 20, label: '20以内' },
          ]}
          onChange={(v) => setTweak('maxSum', v)}
        />
        <TweakSection label="赛道" />
        <TweakSlider
          label="终点距离" value={t.raceLength}
          min={5} max={20} step={1} unit="题"
          onChange={(v) => setTweak('raceLength', v)}
        />
        <TweakToggle
          label="启用道具 ⭐🚀" value={t.powerUpsEnabled}
          onChange={(v) => setTweak('powerUpsEnabled', v)}
        />
        <TweakSection label="声音" />
        <TweakToggle
          label="音效" value={t.soundOn}
          onChange={(v) => setTweak('soundOn', v)}
        />
      </TweaksPanel>
    </div>
  );
}

// ───────────────────────────────────────────────────────────
// Game screen with race track + answer panels
// ───────────────────────────────────────────────────────────
function GameScreen(props) {
  const { players, question, positions, scores, powerUps, raceLength,
          feedback, bonusPops, boostingLane, onAnswer, soundOn, toggleSound } = props;

  return (
    <div className="game" data-screen-label="Game">
      <button
        className="sound-toggle"
        onClick={() => { toggleSound(); GameAudio.play('click'); }}
      >{soundOn ? '🔊' : '🔇'}</button>

      <div className="topbar">
        <Scorecard player={players[0]} which="p1" pos={positions[0]} score={scores[0]} raceLength={raceLength} />
        {question && (
          <div className="qbanner">
            <span>{question.a}</span>
            <span style={{color: 'var(--p1-dark)'}}>+</span>
            <span>{question.b}</span>
            <span style={{color: 'var(--text-soft)'}}>=</span>
            <span className="q-mark">?</span>
          </div>
        )}
        <Scorecard player={players[1]} which="p2" pos={positions[1]} score={scores[1]} raceLength={raceLength} />
      </div>

      <RaceTrack
        players={players}
        positions={positions}
        raceLength={raceLength}
        powerUps={powerUps}
        bonusPops={bonusPops}
        boostingLane={boostingLane}
      />

      {question && (
        <div className="answers">
          <AnswerPanel
            player={players[0]} which="p1" lane={0}
            question={question}
            feedback={feedback[0]}
            onAnswer={onAnswer}
          />
          <AnswerPanel
            player={players[1]} which="p2" lane={1}
            question={question}
            feedback={feedback[1]}
            onAnswer={onAnswer}
          />
        </div>
      )}
    </div>
  );
}

function Scorecard({ player, which, pos, score, raceLength }) {
  const pct = (pos / raceLength) * 100;
  return (
    <div className={"scorecard " + which}>
      <div className="avatar">{player.avatar}</div>
      <div className="info">
        <div className="name">{player.name} <span style={{color:'var(--text-soft)', fontSize: 14}}>· 答对 {score}</span></div>
        <div className="progress"><div className="progress-fill" style={{width: pct + '%'}} /></div>
      </div>
    </div>
  );
}

function AnswerPanel({ player, which, lane, question, feedback, onAnswer }) {
  const fb = feedback;
  return (
    <div className={"apanel " + which}>
      <div className="apanel-title">
        <span className="av">{player.avatar}</span>
        <span>{player.name} 的答案</span>
      </div>
      <div className="answer-grid">
        {question.options.map((opt) => {
          let cls = "ans-btn";
          if (fb && typeof fb === 'object' && fb.wrong === opt) cls += " wrong";
          else if (fb === 'correct' && opt === question.answer) cls += " correct";
          return (
            <button
              key={opt}
              className={cls}
              onClick={() => onAnswer(lane, opt)}
            >{opt}</button>
          );
        })}
      </div>
      {fb === 'correct' && <div className="panel-flash" />}
    </div>
  );
}

// ───────────────────────────────────────────────────────────
// Race track
// ───────────────────────────────────────────────────────────
function RaceTrack({ players, positions, raceLength, powerUps, bonusPops, boostingLane }) {
  // map position 0..raceLength to x% 4..86 (leaving room for car width and finish line)
  const xPctFor = (pos) => 4 + (pos / raceLength) * 82;

  const hasWinner = positions.some(p => p >= raceLength);

  return (
    <div className="track">
      {/* Grass decor */}
      <div className="grass-decor" style={{ top: 8, left: '8%' }}>🌳</div>
      <div className="grass-decor" style={{ top: 6, left: '38%' }}>🌲</div>
      <div className="grass-decor" style={{ top: 4, left: '72%' }}>🌳</div>
      <div className="grass-decor" style={{ bottom: 4, left: '20%' }}>🌼</div>
      <div className="grass-decor" style={{ bottom: 8, left: '55%' }}>🌳</div>
      <div className="grass-decor" style={{ bottom: 6, left: '88%' }}>🌲</div>

      <div className="track-road">
        <div className="lane-edge top" />
        <div className="lane-divider" />
        <div className="lane-edge bottom" />
      </div>

      <div className="start-line" />
      <div className="finish-line" />
      <div className="finish-flag">🏁</div>

      {/* Power-ups */}
      <div className="car-track-layer">
        {powerUps.map((p) => (
          <div
            key={p.id}
            className={"power-up lane-" + (p.lane + 1) + (p.collected ? " collected" : "")}
            style={{ left: 'calc(' + xPctFor(p.position) + '% + 15px)' }}
          >
            {p.type === 'star' ? '⭐' : '🚀'}
          </div>
        ))}

        {/* Cars */}
        {players.map((pl, i) => {
          const isWinner = hasWinner && positions[i] >= raceLength;
          return (
            <div
              key={i}
              className={"car-wrap lane-" + (i + 1)}
              style={{ left: 'calc(' + xPctFor(positions[i]) + '% - 30px)' }}
            >
              <Car
                color={pl.color}
                dark={pl.dark}
                soft={pl.soft}
                avatar={pl.avatar}
                boost={boostingLane === i}
                winner={isWinner}
              />
            </div>
          );
        })}

        {/* Bonus popups */}
        {bonusPops.map((bp) => (
          <div
            key={bp.id}
            className="bonus-pop"
            style={{
              left: 'calc(' + xPctFor(positions[bp.lane]) + '% + 30px)',
              top: bp.lane === 0 ? 'calc(50% - 90px)' : 'calc(50% + 30px)',
            }}
          >+{bp.amount}</div>
        ))}
      </div>
    </div>
  );
}

// ───────────────────────────────────────────────────────────
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
