import { useEffect, useLayoutEffect, useRef, useState } from "react";
import { LayoutGroup, motion } from "motion/react";
import {
  ArrowDown,
  ArrowLeft,
  ArrowRight,
  ArrowUp,
  ChartLineUp,
  Check,
  CheckCircle,
  ClockCountdown,
  Heart,
  LockKey,
  Minus,
  Path,
  Sparkle,
  Speedometer,
  SquaresFour,
  Star,
  Target,
  Timer,
  X,
} from "@phosphor-icons/react";

type Screen = "home" | "profile" | "overview" | "symbol" | "trail" | "attention" | "memory" | "money" | "complete" | "report";
type Game = "symbol" | "trail" | "attention" | "memory" | "money";
type Direction = "up" | "right" | "down" | "left";
type MetricKey = "speed" | "executive" | "attention" | "memory" | "calculation";
type Metric = { score: number; correct: number; total: number; errors: number; completion: number };
type Plane = { id: number; color: "blue" | "orange"; direction: Direction; lane: number; duration: number; delay: number; target: boolean };

const SYMBOL_IMAGES = [
  "/assets/brain/symbols/camera.png",
  "/assets/brain/symbols/sun.png",
  "/assets/brain/symbols/squares.png",
  "/assets/brain/symbols/lock.png",
  "/assets/brain/symbols/lightning.png",
  "/assets/brain/symbols/moon.png",
  "/assets/brain/symbols/gear.png",
  "/assets/brain/symbols/star.png",
  "/assets/brain/symbols/puzzle.png",
  "/assets/brain/symbols/coffee.png",
] as const;

const FOODS = [
  { name: "全麦面包", image: "/assets/brain/memory/bread.png", tone: "amber" },
  { name: "胡萝卜", image: "/assets/brain/memory/carrot.png", tone: "coral" },
  { name: "奶酪", image: "/assets/brain/memory/cheese.png", tone: "yellow" },
  { name: "咖啡", image: "/assets/brain/memory/coffee.png", tone: "violet" },
  { name: "曲奇", image: "/assets/brain/memory/cookie.png", tone: "pink" },
  { name: "鸡蛋", image: "/assets/brain/memory/egg.png", tone: "blue" },
  { name: "鲜鱼", image: "/assets/brain/memory/fish.png", tone: "cyan" },
  { name: "橙子", image: "/assets/brain/memory/orange.png", tone: "orange" },
] as const;

const PLANE_IMAGE = {
  blue: "/assets/brain/planes/teal.png",
  orange: "/assets/brain/planes/coral.png",
} as const;

const COMPLETION_IMAGES: Record<Game, string> = {
  symbol: "/assets/ui/finish-symbol.png",
  trail: "/assets/ui/finish-trail.png",
  attention: "/assets/ui/finish-attention.png",
  memory: "/assets/ui/finish-memory.png",
  money: "/assets/ui/finish-all.png",
};

const DIRECTIONS: Direction[] = ["up", "right", "down", "left"];
const DIRECTION_ICONS = { up: ArrowUp, right: ArrowRight, down: ArrowDown, left: ArrowLeft };
const DIRECTION_LABELS = { up: "向上", right: "向右", down: "向下", left: "向左" };
const DIRECTION_ANGLE = { up: -90, right: 0, down: 90, left: 180 };
const EMPTY_METRIC: Metric = { score: 0, correct: 0, total: 0, errors: 0, completion: 0 };
const MONEY_OPTIONS = [
  { value: 0.5, image: "/assets/money/money-05.png" },
  { value: 1, image: "/assets/money/money-1.png" },
  { value: 2, image: "/assets/money/money-2.png" },
  { value: 5, image: "/assets/money/money-5.png" },
  { value: 10, image: "/assets/money/money-10.png" },
  { value: 20, image: "/assets/money/money-20.png" },
] as const;
const MEMORY_ROUND_SECONDS = [0, 35, 40, 45];
const MONEY_ROUNDS = [
  { price: 13, payment: 20, target: 7, seconds: 40 },
  { price: 26.5, payment: 40, target: 13.5, seconds: 45 },
  { price: 41.5, payment: 60, target: 18.5, seconds: 50 },
] as const;

function moneyImage(value: number) {
  return MONEY_OPTIONS.find((option) => option.value === value)?.image ?? MONEY_OPTIONS[0].image;
}

const TRAIL_NODES = Array.from({ length: 20 }, (_, index) => ({
  kind: index % 2 === 0 ? ("number" as const) : ("shape" as const),
  rank: Math.floor(index / 2) + 1,
}));

const TRAIL_PATH = [
  { x: 42, y: 58 }, { x: 57, y: 43 }, { x: 74, y: 54 }, { x: 66, y: 69 },
  { x: 50, y: 75 }, { x: 34, y: 65 }, { x: 18, y: 78 }, { x: 11, y: 58 },
  { x: 24, y: 43 }, { x: 14, y: 25 }, { x: 31, y: 16 }, { x: 45, y: 29 },
  { x: 57, y: 15 }, { x: 69, y: 31 }, { x: 80, y: 17 }, { x: 91, y: 31 },
  { x: 84, y: 48 }, { x: 92, y: 68 }, { x: 78, y: 82 }, { x: 58, y: 85 },
];

function shuffle<T>(items: readonly T[]) {
  const copy = [...items];
  for (let i = copy.length - 1; i > 0; i -= 1) {
    const j = Math.floor(Math.random() * (i + 1));
    [copy[i], copy[j]] = [copy[j], copy[i]];
  }
  return copy;
}

function randomDirection(): Direction {
  return DIRECTIONS[Math.floor(Math.random() * DIRECTIONS.length)];
}

function scoreMetric(correct: number, total: number, errors: number, expected: number): Metric {
  const completion = Math.min(1, total / expected);
  const attempts = Math.max(total, correct + errors);
  const accuracy = attempts ? correct / attempts : 0;
  const score = Math.max(20, Math.min(98, Math.round(accuracy * 72 + completion * 28)));
  return { score, correct, total, errors, completion: Math.round(completion * 100) };
}

function createTrailLayout() {
  const flipX = Math.random() > 0.5;
  const flipY = Math.random() > 0.5;
  return TRAIL_PATH.map((point, index) => ({
    x: (flipX ? 100 - point.x : point.x) + (index % 3 - 1) * 0.7,
    y: (flipY ? 100 - point.y : point.y) + ((index + 1) % 3 - 1) * 0.6,
  }));
}

function createPlanes(trial: number, targetColor: "blue" | "orange", targetDirection: Direction): Plane[] {
  const count = trial < 3 ? 1 : trial < 10 ? 3 : trial < 20 ? 5 : 7;
  const targetIndex = Math.floor(Math.random() * count);
  return Array.from({ length: count }, (_, index) => {
    const target = index === targetIndex;
    // Keep the requested color unique. Distractors are always the opposite color.
    const color = target ? targetColor : targetColor === "blue" ? "orange" : "blue";
    return {
      id: Date.now() + index,
      target,
      direction: target ? targetDirection : randomDirection(),
      color,
      lane: 12 + ((index * 17 + Math.floor(Math.random() * 10)) % 72),
      duration: 6.7 + Math.random() * 1.5,
      delay: index * 0.38,
    };
  });
}

function Brand() {
  return (
    <div className="brand">
      <span><SquaresFour size={24} weight="fill" /></span>
      <b>脑晴测</b>
      <em>COGNITIVE STUDIO</em>
    </div>
  );
}

function PrimaryButton({ children, onClick, disabled, secondary = false }: {
  children: React.ReactNode;
  onClick: () => void;
  disabled?: boolean;
  secondary?: boolean;
}) {
  return <button className={`primary-button ${secondary ? "secondary" : ""}`} onClick={onClick} disabled={disabled}>{children}</button>;
}

function GameHeader({ seconds, onBack }: { seconds: number; onBack: () => void }) {
  return (
    <header className="game-header">
      <button className="round-button" onClick={onBack} aria-label="退出当前测试"><ArrowLeft weight="bold" /></button>
      <div className="timer"><Timer weight="fill" /><b>{String(Math.floor(seconds / 60)).padStart(2, "0")}:{String(seconds % 60).padStart(2, "0")}</b></div>
    </header>
  );
}

function GameIntro({ game, onStart }: { game: Game; onStart: () => void }) {
  const info = {
    symbol: { no: "01", title: "符号速配", text: "记住固定符号表，看到目标后选择对应数字。", rules: ["映射表全程固定", "准确优先，再提高速度", "完成练习后开始"] },
    trail: { no: "02", title: "交替连线", text: "按照数字与绿色扇区交替、从小到大的顺序连接。", rules: ["1 到最小扇区再到 2", "扇区面积逐级增加", "错误不会推进进度"] },
    attention: { no: "03", title: "动态方向追踪", text: "根据顶部目标颜色，在飞行中的机群里判断目标飞机头朝向。", rules: ["飞机持续移动", "目标颜色每题变化", "三次错误后结束"] },
    memory: { no: "04", title: "购物记忆", text: "先记住清单，再从移动的传送带上选中对应商品。", rules: ["商品依次移动出现", "每轮难度逐渐增加", "中途回看会影响评分"] },
    money: { no: "05", title: "零钱计算", text: "根据应找金额，组合出完全一致的钱币数值。", rules: ["直接点击钱币", "点击已选钱币可撤回", "完成两轮精确找零"] },
  }[game];
  const [practised, setPractised] = useState(false);
  const [practiceStep, setPracticeStep] = useState(0);
  const [practicePick, setPracticePick] = useState<number | null>(null);

  const finishPractice = () => {
    setPractised(true);
  };

  const practiceContent = {
    symbol: (
      <div className="practice-panel symbol-practice">
        <div className="coach-hint"><span><b>先看这里</b> 找到图标对应的数字</span><ArrowDown weight="bold" /></div>
        <img src={SYMBOL_IMAGES[2]} alt="" />
        <div className="practice-key-row">{[1, 2, 3].map((number) => <button key={number} className={practicePick === number ? "picked" : ""} onClick={() => { setPracticePick(number); if (number === 2) finishPractice(); }}>{number}</button>)}</div>
      </div>
    ),
    trail: (
      <div className="practice-panel trail-practice">
        <div className="coach-hint"><span><b>按箭头顺序</b> 先点 1，再点最小扇区，最后点 2</span><ArrowDown weight="bold" /></div>
        {[0, 1, 2].map((index) => <button key={index} className={practiceStep > index ? "done" : ""} onClick={() => { if (practiceStep === index) { const next = practiceStep + 1; setPracticeStep(next); if (next === 3) finishPractice(); } }}>{index === 1 ? <i /> : index === 0 ? "1" : "2"}</button>)}
      </div>
    ),
    attention: (
      <div className="practice-panel attention-practice">
        <div className="coach-hint"><span><b>观察机头</b> 这架飞机朝右，点击右方向键</span><ArrowDown weight="bold" /></div>
        <img src={PLANE_IMAGE.blue} alt="" />
        <div className="practice-directions">{DIRECTIONS.map((direction) => { const Icon = DIRECTION_ICONS[direction]; return <button className={`direction-${direction}`} key={direction} onClick={() => { if (direction === "right") finishPractice(); }}><Icon weight="bold" /></button>; })}</div>
      </div>
    ),
    memory: (
      <div className="practice-panel memory-practice">
        <div className="coach-hint"><span><b>{practiceStep === 0 ? "先记住清单" : "现在动手选择"}</b> {practiceStep === 0 ? "点击任意商品进入选择练习" : "点击清单里的曲奇"}</span><ArrowDown weight="bold" /></div>
        <div>{[1, 4, 7].map((index) => <button key={index} className={practicePick === index ? "picked" : ""} onClick={() => { if (practiceStep === 0) { setPracticeStep(1); return; } setPracticePick(index); if (index === 4) finishPractice(); }}><img src={FOODS[index].image} alt="" /></button>)}</div>
      </div>
    ),
    money: (
      <div className="practice-panel memory-practice">
        <div className="coach-hint"><span><b>组合 7 元</b> 依次点击 5 元和 2 元</span><ArrowDown weight="bold" /></div>
        <div>{MONEY_OPTIONS.filter((option) => option.value === 5 || option.value === 2).map((option) => <button key={option.value} onClick={() => finishPractice()}><img src={option.image} alt={`${option.value} 元`} /></button>)}</div>
      </div>
    ),
  }[game];

  return (
    <div className="intro-backdrop">
      <section className={`intro-card tutorial-card tutorial-${game}`}>
        <header className="tutorial-head"><span>练习 {info.no}</span><h2>{info.title}</h2><p>{info.text}</p></header>
        {practiceContent}
        <div className={`practice-trigger ${practised ? "done" : ""}`}>
          {practised ? <><Check weight="bold" /> 已掌握操作</> : <><ArrowUp weight="bold" /> 按提示点击高亮位置</>}
        </div>
        <PrimaryButton disabled={!practised} onClick={onStart}>开始正式测试 <ArrowRight weight="bold" /></PrimaryButton>
      </section>
    </div>
  );
}

function CoachOverlay({ target, text, onTargetClick }: { target: string; text: string; onTargetClick: () => void }) {
  const [rect, setRect] = useState<{ left: number; top: number; width: number; height: number } | null>(null);

  useLayoutEffect(() => {
    const update = () => {
      const element = document.querySelector<HTMLElement>(target);
      if (!element) return;
      const bounds = element.getBoundingClientRect();
      const padding = 9;
      setRect({
        left: Math.max(4, bounds.left - padding),
        top: Math.max(4, bounds.top - padding),
        width: Math.min(window.innerWidth - 8, bounds.width + padding * 2),
        height: Math.min(window.innerHeight - 8, bounds.height + padding * 2),
      });
    };
    update();
    const observer = new ResizeObserver(update);
    const element = document.querySelector<HTMLElement>(target);
    if (element) observer.observe(element);
    window.addEventListener("resize", update);
    return () => {
      observer.disconnect();
      window.removeEventListener("resize", update);
    };
  }, [target]);

  if (!rect) return null;
  const bubbleWidth = Math.min(292, window.innerWidth - 24);
  const below = rect.top < window.innerHeight * 0.42;
  const bubbleLeft = Math.max(12, Math.min(window.innerWidth - bubbleWidth - 12, rect.left + rect.width / 2 - bubbleWidth / 2));
  const bubbleTop = below ? Math.min(window.innerHeight - 132, rect.top + rect.height + 22) : Math.max(12, rect.top - 118);

  return (
    <div className="coach-layer" aria-live="polite">
      <div className="coach-shade coach-shade-top" style={{ height: rect.top }} />
      <div className="coach-shade coach-shade-left" style={{ top: rect.top, width: rect.left, height: rect.height }} />
      <div className="coach-shade coach-shade-right" style={{ top: rect.top, left: rect.left + rect.width, height: rect.height }} />
      <div className="coach-shade coach-shade-bottom" style={{ top: rect.top + rect.height }} />
      <div className="coach-spotlight" style={rect} />
      <button className="coach-hit-target" style={rect} onClick={onTargetClick} aria-label="点击高亮位置" />
      <div className={`coach-bubble ${below ? "below" : "above"}`} style={{ left: bubbleLeft, top: bubbleTop, width: bubbleWidth }}>
        <b>跟着提示操作</b>
        <span>{text}</span>
      </div>
    </div>
  );
}

function DemoReadyOverlay({ onStart }: { onStart: () => void }) {
  return (
    <div className="demo-ready-layer">
      <CheckCircle weight="fill" />
      <p>试玩完成</p>
      <h2>已经掌握操作</h2>
      <PrimaryButton onClick={onStart}>开始正式游戏 <ArrowRight weight="bold" /></PrimaryButton>
    </div>
  );
}

export default function Prototype() {
  const [screen, setScreen] = useState<Screen>("home");
  const [intro, setIntro] = useState<Game | null>(null);
  const [profile, setProfile] = useState({ age: "", gender: "", education: "" });
  const [seconds, setSeconds] = useState(60);
  const [feedback, setFeedback] = useState<"correct" | "wrong" | null>(null);
  const [exitConfirm, setExitConfirm] = useState(false);
  const [coachStep, setCoachStep] = useState(0);
  const [completedGame, setCompletedGame] = useState<Game>("symbol");
  const [completionNext, setCompletionNext] = useState<Screen>("trail");
  const [metrics, setMetrics] = useState<Record<MetricKey, Metric>>({
    speed: EMPTY_METRIC,
    executive: EMPTY_METRIC,
    attention: EMPTY_METRIC,
    memory: EMPTY_METRIC,
    calculation: EMPTY_METRIC,
  });

  const [symbolTrial, setSymbolTrial] = useState(0);
  const [symbolTarget, setSymbolTarget] = useState(0);
  const [symbolMap, setSymbolMap] = useState(() => shuffle(Array.from({ length: 10 }, (_, index) => index)));
  const symbolCorrect = useRef(0);
  const symbolErrors = useRef(0);

  const [trailIndex, setTrailIndex] = useState(0);
  const [trailPositions, setTrailPositions] = useState(createTrailLayout);
  const trailErrors = useRef(0);

  const [attentionTrial, setAttentionTrial] = useState(0);
  const [attentionDirection, setAttentionDirection] = useState<Direction>("right");
  const [targetColor, setTargetColor] = useState<"blue" | "orange">("blue");
  const [attentionLives, setAttentionLives] = useState(3);
  const [planes, setPlanes] = useState<Plane[]>(() => createPlanes(0, "blue", "right"));
  const attentionCorrect = useRef(0);
  const attentionErrors = useRef(0);

  const [memoryRound, setMemoryRound] = useState(1);
  const [memoryPhase, setMemoryPhase] = useState<"study" | "conveyor">("study");
  const [memoryTargets, setMemoryTargets] = useState<number[]>(() => shuffle([0, 1, 2, 3, 4, 5, 6, 7]).slice(0, 2));
  const [memorySelected, setMemorySelected] = useState<number[]>([]);
  const [memoryRetired, setMemoryRetired] = useState<number[]>([]);
  const [beltOrder, setBeltOrder] = useState<number[]>(() => shuffle([0, 1, 2, 3, 4, 5, 6, 7]));
  const [listOpen, setListOpen] = useState(false);
  const [moneyRound, setMoneyRound] = useState(1);
  const [moneyAttempts, setMoneyAttempts] = useState(0);
  const [cash, setCash] = useState<number[]>([]);
  const memoryCorrect = useRef(0);
  const memoryTotal = useRef(0);
  const memoryErrors = useRef(0);
  const memoryListViews = useRef(0);
  const memoryListViewMs = useRef(0);
  const listOpenedAt = useRef<number | null>(null);
  const beltRetireTimers = useRef<number[]>([]);
  const calculationCorrect = useRef(0);
  const calculationTotal = useRef(0);
  const calculationErrors = useRef(0);

  const activeGame = ["symbol", "trail", "attention", "memory", "money"].includes(screen) && !intro && !exitConfirm;
  const timerActive = activeGame && !(screen === "memory" && (memoryPhase === "study" || listOpen));

  useEffect(() => {
    if (!timerActive || seconds <= 0) return;
    const timer = window.setInterval(() => setSeconds((value) => value - 1), 1000);
    return () => window.clearInterval(timer);
  }, [timerActive, seconds]);

  useEffect(() => {
    window.scrollTo({ top: 0, behavior: "smooth" });
  }, [screen]);

  const flash = (value: "correct" | "wrong") => {
    setFeedback(value);
    window.setTimeout(() => setFeedback(null), 620);
  };

  const closeMemoryList = () => {
    if (intro !== "memory" && listOpenedAt.current !== null) {
      memoryListViewMs.current += Date.now() - listOpenedAt.current;
      listOpenedAt.current = null;
    }
    setListOpen(false);
  };

  const toggleMemoryList = () => {
    if (listOpen) {
      closeMemoryList();
      return;
    }
    if (intro !== "memory") {
      memoryListViews.current += 1;
      listOpenedAt.current = Date.now();
    }
    setListOpen(true);
  };

  const memoryMetric = () => {
    const base = scoreMetric(memoryCorrect.current, memoryTotal.current, memoryErrors.current, 9);
    const viewSeconds = Math.round(memoryListViewMs.current / 1000);
    const reviewPenalty = Math.min(20, memoryListViews.current * 4 + Math.floor(viewSeconds / 5));
    return { ...base, score: Math.max(20, base.score - reviewPenalty) };
  };

  const openGame = (game: Game) => {
    setScreen(game);
    setIntro(game);
    setCoachStep(0);
    setListOpen(false);
  };

  const clearBeltRetireTimers = () => {
    beltRetireTimers.current.forEach((timer) => window.clearTimeout(timer));
    beltRetireTimers.current = [];
  };

  const startGame = (game: Game) => {
    setIntro(null);
    setSeconds(game === "trail" ? 90 : game === "memory" ? MEMORY_ROUND_SECONDS[1] : 60);
    if (game === "symbol") {
      let nextTarget = Math.floor(Math.random() * 10);
      while (nextTarget === symbolTarget) nextTarget = Math.floor(Math.random() * 10);
      setSymbolTrial(0);
      setSymbolTarget(nextTarget);
      setSymbolMap(shuffle(Array.from({ length: 10 }, (_, index) => index)));
      symbolCorrect.current = 0;
      symbolErrors.current = 0;
    }
    if (game === "trail") {
      let nextLayout = createTrailLayout();
      let attempts = 0;
      while (nextLayout.every((point, index) => point.x === trailPositions[index].x && point.y === trailPositions[index].y) && attempts < 6) {
        nextLayout = createTrailLayout();
        attempts += 1;
      }
      setTrailIndex(0);
      setTrailPositions(nextLayout);
      trailErrors.current = 0;
    }
    if (game === "attention") {
      const direction = DIRECTIONS[(DIRECTIONS.indexOf(attentionDirection) + 1 + Math.floor(Math.random() * 3)) % DIRECTIONS.length];
      const color = Math.random() > 0.5 ? "blue" : "orange";
      setAttentionTrial(0);
      setAttentionLives(3);
      setAttentionDirection(direction);
      setTargetColor(color);
      setPlanes(createPlanes(0, color, direction));
      attentionCorrect.current = 0;
      attentionErrors.current = 0;
    }
    if (game === "memory") {
      let nextTargets = shuffle([0, 1, 2, 3, 4, 5, 6, 7]).slice(0, 2);
      const demoKey = [...memoryTargets.slice(0, 2)].sort().join("-");
      while ([...nextTargets].sort().join("-") === demoKey) {
        nextTargets = shuffle([0, 1, 2, 3, 4, 5, 6, 7]).slice(0, 2);
      }
      setMemoryRound(1);
      setMemoryPhase("study");
      setMemoryTargets(nextTargets);
      setMemorySelected([]);
      setMemoryRetired([]);
      setBeltOrder(shuffle([0, 1, 2, 3, 4, 5, 6, 7]));
      setListOpen(false);
      setCash([]);
      memoryCorrect.current = 0;
      memoryTotal.current = 0;
      memoryErrors.current = 0;
      memoryListViews.current = 0;
      memoryListViewMs.current = 0;
      listOpenedAt.current = null;
    }
    if (game === "money") {
      setMoneyRound(1);
      setMoneyAttempts(0);
      setCash([]);
      setSeconds(MONEY_ROUNDS[0].seconds);
      calculationCorrect.current = 0;
      calculationTotal.current = 0;
      calculationErrors.current = 0;
    }
  };

  const finishGame = (key: MetricKey, metric: Metric, next: Screen) => {
    setMetrics((current) => ({ ...current, [key]: metric }));
    setCompletedGame(screen as Game);
    setCompletionNext(next);
    setScreen("complete");
    setIntro(null);
  };

  const finishMoneyRound = (correct: boolean) => {
    calculationTotal.current += 1;
    if (correct) calculationCorrect.current += 1;
    setCash([]);
    setMoneyAttempts(0);
    if (moneyRound < MONEY_ROUNDS.length) {
      const nextRound = moneyRound + 1;
      setMoneyRound(nextRound);
      setSeconds(MONEY_ROUNDS[nextRound - 1].seconds);
      return;
    }
    finishGame("calculation", scoreMetric(calculationCorrect.current, calculationTotal.current, calculationErrors.current, MONEY_ROUNDS.length), "report");
  };

  const continueAfterTime = () => {
    if (screen === "symbol") finishGame("speed", scoreMetric(symbolCorrect.current, symbolTrial, symbolErrors.current, 30), "trail");
    if (screen === "trail") finishGame("executive", scoreMetric(trailIndex, trailIndex, trailErrors.current, 20), "attention");
    if (screen === "attention") finishGame("attention", scoreMetric(attentionCorrect.current, attentionTrial, attentionErrors.current, 20), "memory");
    if (screen === "memory" && memoryPhase === "conveyor") finishMemoryRound(memorySelected);
    if (screen === "money") {
      calculationErrors.current += 1;
      finishMoneyRound(false);
    }
  };

  useEffect(() => {
    if (!timerActive || seconds !== 0) return;
    continueAfterTime();
  }, [timerActive, seconds]);

  const resetAll = () => {
    setMetrics({ speed: EMPTY_METRIC, executive: EMPTY_METRIC, attention: EMPTY_METRIC, memory: EMPTY_METRIC, calculation: EMPTY_METRIC });
    setSymbolTrial(0);
    setSymbolMap(shuffle(Array.from({ length: 10 }, (_, index) => index)));
    setSymbolTarget(Math.floor(Math.random() * 10));
    symbolCorrect.current = 0;
    symbolErrors.current = 0;
    setTrailIndex(0);
    setTrailPositions(createTrailLayout());
    trailErrors.current = 0;
    setAttentionTrial(0);
    setAttentionLives(3);
    setAttentionDirection("right");
    setTargetColor("blue");
    setPlanes(createPlanes(0, "blue", "right"));
    attentionCorrect.current = 0;
    attentionErrors.current = 0;
    setMemoryRound(1);
    setMemoryPhase("study");
    setMemoryTargets(shuffle([0, 1, 2, 3, 4, 5, 6, 7]).slice(0, 2));
    setMemorySelected([]);
    setMemoryRetired([]);
    setBeltOrder(shuffle([0, 1, 2, 3, 4, 5, 6, 7]));
    setCash([]);
    memoryCorrect.current = 0;
    memoryTotal.current = 0;
    memoryErrors.current = 0;
    memoryListViews.current = 0;
    memoryListViewMs.current = 0;
    listOpenedAt.current = null;
    setMoneyRound(1);
    setMoneyAttempts(0);
    setCash([]);
    calculationCorrect.current = 0;
    calculationTotal.current = 0;
    calculationErrors.current = 0;
  };

  const answerSymbol = (answer: number) => {
    if (intro === "symbol") {
      if (answer !== symbolMap.indexOf(symbolTarget)) return;
      flash("correct");
      if (coachStep >= 1) {
        setCoachStep(2);
        return;
      }
      let next = Math.floor(Math.random() * 10);
      while (next === symbolTarget) next = Math.floor(Math.random() * 10);
      setSymbolTarget(next);
      setSymbolMap((current) => shuffle(current));
      setCoachStep(1);
      return;
    }
    const correct = symbolMap.indexOf(symbolTarget) === answer;
    if (correct) symbolCorrect.current += 1;
    else symbolErrors.current += 1;
    flash(correct ? "correct" : "wrong");
    if (symbolTrial >= 29) {
      finishGame("speed", scoreMetric(symbolCorrect.current, 30, symbolErrors.current, 30), "trail");
      return;
    }
    let next = Math.floor(Math.random() * 10);
    while (next === symbolTarget) next = Math.floor(Math.random() * 10);
    setSymbolTarget(next);
    setSymbolMap((current) => shuffle(current));
    setSymbolTrial((value) => value + 1);
  };

  const tapTrail = (index: number) => {
    if (intro === "trail") {
      if (index !== coachStep) return;
      flash("correct");
      setCoachStep((value) => value >= 3 ? 4 : value + 1);
      return;
    }
    if (index !== trailIndex) {
      trailErrors.current += 1;
      flash("wrong");
      return;
    }
    flash("correct");
    if (index === 19) {
      finishGame("executive", scoreMetric(20, 20, trailErrors.current, 20), "attention");
      return;
    }
    setTrailIndex(index + 1);
  };

  const answerAttention = (direction: Direction) => {
    if (intro === "attention") {
      if (direction !== attentionDirection) return;
      flash("correct");
      if (coachStep >= 1) {
        setCoachStep(2);
        return;
      }
      const nextDirection = DIRECTIONS[(DIRECTIONS.indexOf(attentionDirection) + 1 + Math.floor(Math.random() * 3)) % DIRECTIONS.length];
      setAttentionDirection(nextDirection);
      setTargetColor((color) => color === "blue" ? "orange" : "blue");
      setCoachStep(1);
      return;
    }
    const correct = direction === attentionDirection;
    if (correct) attentionCorrect.current += 1;
    else {
      attentionErrors.current += 1;
      setAttentionLives((value) => Math.max(0, value - 1));
    }
    flash(correct ? "correct" : "wrong");
    const nextLives = correct ? attentionLives : attentionLives - 1;
    if (attentionTrial >= 19 || nextLives <= 0) {
      finishGame("attention", scoreMetric(attentionCorrect.current, attentionTrial + 1, attentionErrors.current, 20), "memory");
      return;
    }
    const nextTrial = attentionTrial + 1;
    const nextDirection = randomDirection();
    const nextColor = Math.random() > 0.5 ? "blue" : "orange";
    setAttentionTrial(nextTrial);
    setAttentionDirection(nextDirection);
    setTargetColor(nextColor);
    setPlanes(createPlanes(nextTrial, nextColor, nextDirection));
  };

  const finishMemoryRound = (selected: number[]) => {
    clearBeltRetireTimers();
    const hits = memoryTargets.filter((item) => selected.includes(item)).length;
    const wrong = selected.filter((item) => !memoryTargets.includes(item)).length;
    memoryCorrect.current += hits;
    memoryTotal.current += memoryTargets.length;
    memoryErrors.current += wrong + memoryTargets.length - hits;
    flash(wrong === 0 && hits === memoryTargets.length ? "correct" : "wrong");
    if (memoryRound < 3) {
      const nextRound = memoryRound + 1;
      setMemoryRound(nextRound);
      setMemoryTargets(shuffle([0, 1, 2, 3, 4, 5, 6, 7]).slice(0, nextRound + 1));
      setMemorySelected([]);
      setMemoryRetired([]);
      setBeltOrder(shuffle([0, 1, 2, 3, 4, 5, 6, 7]));
      setMemoryPhase("study");
      setSeconds(MEMORY_ROUND_SECONDS[nextRound]);
    } else {
      closeMemoryList();
      finishGame("memory", memoryMetric(), "money");
    }
  };

  const selectMemoryItem = (index: number, element?: HTMLButtonElement) => {
    if (memoryTargets.every((target) => memorySelected.includes(target))) return;
    if (memorySelected.includes(index)) return;
    if (!memoryTargets.includes(index)) {
      memoryErrors.current += 1;
      flash("wrong");
      return;
    }
    const next = [...memorySelected, index];
    setMemorySelected(next);
    flash("correct");
    if (memoryTargets.every((target) => next.includes(target))) {
      window.setTimeout(() => finishMemoryRound(next), 180);
      return;
    }
    if (!element) return;
    const timer = window.setInterval(() => {
      if (!document.body.contains(element)) {
        window.clearInterval(timer);
        return;
      }
      if (element.getBoundingClientRect().left <= window.innerWidth) return;
      window.clearInterval(timer);
      setMemoryRetired((current) => current.includes(index) ? current : [...current, index]);
    }, 120);
    beltRetireTimers.current.push(timer);
  };

  const moneyQuestion = MONEY_ROUNDS[moneyRound - 1];
  const changeTarget = moneyQuestion.target;
  const cashTotal = cash.reduce((sum, item) => sum + item, 0);
  const submitChange = () => {
    const correct = Math.abs(cashTotal - changeTarget) < 0.01;
    flash(correct ? "correct" : "wrong");
    if (correct) {
      finishMoneyRound(true);
      return;
    }
    calculationErrors.current += 1;
    if (moneyAttempts === 0) {
      setMoneyAttempts(1);
      setCash([]);
      return;
    }
    finishMoneyRound(false);
  };

  const completeMemoryDemo = (index: number) => {
    const demoTarget = memoryTargets[coachStep - 2];
    if (intro !== "memory" || coachStep < 2 || coachStep > 3 || index !== demoTarget) return;
    flash("correct");
    setCoachStep((value) => value + 1);
  };

  const completeMoneyDemo = (value: number) => {
    if (intro !== "money") return;
    if (coachStep === 0 && value === 1) {
      setCash([1]);
      setCoachStep(1);
    } else if (coachStep === 1 && value === 2) {
      setCash([1, 2]);
      setCoachStep(2);
    }
  };

  const removeCash = (index: number) => {
    setCash((items) => items.filter((_, itemIndex) => itemIndex !== index));
  };

  const continueFromCompletion = () => {
    if (completionNext === "report") {
      setScreen("report");
      return;
    }
    openGame(completionNext as Game);
  };

  const overall = Math.round(Object.values(metrics).reduce((sum, metric) => sum + (metric.score || 70), 0) / 5);
  const reportRows: Array<[MetricKey, string, typeof Speedometer]> = [
    ["speed", "处理速度", Speedometer],
    ["executive", "执行功能", Path],
    ["attention", "注意力", Target],
    ["memory", "工作记忆", SquaresFour],
    ["calculation", "计算能力", ChartLineUp],
  ];
  const rankedMetrics = [...reportRows].sort((a, b) => metrics[b[0]].score - metrics[a[0]].score);
  const strongestMetric = rankedMetrics[0][1];
  const improvementMetric = rankedMetrics[rankedMetrics.length - 1][1];
  const totalCorrect = Object.values(metrics).reduce((sum, metric) => sum + metric.correct, 0);
  const totalErrors = Object.values(metrics).reduce((sum, metric) => sum + metric.errors, 0);
  const averageCompletion = Math.round(Object.values(metrics).reduce((sum, metric) => sum + metric.completion, 0) / 5);
  const memoryReviewSeconds = Math.round(memoryListViewMs.current / 1000);
  const completedGameName = {
    symbol: "符号速配",
    trail: "交替连线",
    attention: "方向追踪",
    memory: "购物记忆",
    money: "零钱计算",
  }[completedGame];
  const demoReady = intro === "symbol" ? coachStep >= 2
    : intro === "trail" ? coachStep >= 4
      : intro === "attention" ? coachStep >= 2
        : intro === "memory" ? coachStep >= 4
          : intro === "money" ? coachStep >= 2
          : false;
  const coach = !demoReady && intro === "symbol"
    ? {
        target: `.keypad button[data-number="${symbolMap.indexOf(symbolTarget)}"]`,
        text: coachStep === 0 ? "完成第一次试玩：找到目标图标对应的数字并点击。" : "图标已经换位，再完成一次匹配。",
        onTargetClick: () => answerSymbol(symbolMap.indexOf(symbolTarget)),
      }
    : !demoReady && intro === "trail"
      ? {
          target: `.trail-node[data-index="${coachStep}"]`,
          text: coachStep === 0 ? "先点击数字 1。" : coachStep === 1 ? "接着点击最小的绿色扇区。" : coachStep === 2 ? "然后点击数字 2。" : "再点击第二小的绿色扇区，完成试玩。",
          onTargetClick: () => tapTrail(coachStep),
        }
      : !demoReady && intro === "attention"
        ? {
            target: `.direction-console button[data-direction="${attentionDirection}"]`,
            text: `${coachStep === 0 ? "第一次试玩" : "再试一次"}：目标是${targetColor === "blue" ? "青绿色" : "珊瑚色"}飞机，点击机头对应的方向键。`,
            onTargetClick: () => answerAttention(attentionDirection),
          }
        : !demoReady && intro === "memory"
          ? coachStep === 0
            ? {
                target: ".memory-demo-stage .shopping-tab",
                text: "先点击购物清单，把需要寻找的商品图片展开。",
                onTargetClick: () => {
                  setListOpen(true);
                  setCoachStep(1);
                },
              }
            : coachStep === 1
              ? {
                  target: ".memory-demo-stage .shopping-tab",
                  text: "记住清单后先收起，传送带才会继续。",
                  onTargetClick: () => {
                    setListOpen(false);
                    setCoachStep(2);
                  },
                }
              : coachStep < 4
                ? {
                  target: `.memory-demo-stage .demo-belt-item[data-index="${memoryTargets[coachStep - 2]}"]`,
                  text: coachStep === 2 ? "点击清单中的第一个商品。" : "再点击清单中的第二个商品。",
                  onTargetClick: () => completeMemoryDemo(memoryTargets[coachStep - 2]),
                }
                : null
          : !demoReady && intro === "money"
            ? {
                target: `.demo-change-stage .money-pad button[data-value="${coachStep === 0 ? 1 : 2}"]`,
                text: coachStep === 0 ? "试玩目标是 3 元，先选择 1 元。" : "再选择 2 元，组成 3 元，完成试玩。",
                onTargetClick: () => completeMoneyDemo(coachStep === 0 ? 1 : 2),
              }
          : null;

  return (
    <div className={`web-app screen-${screen}`}>
      {screen === "home" && (
        <main className="landing-shell">
          <nav><Brand /><span className="home-duration"><Timer weight="fill" /> 约 10 分钟</span></nav>
          <section className="home-start">
            <header className="home-copy">
              <img className="home-visual" src="/assets/ui/home-compass.png" alt="" />
              <p className="eyebrow"><Sparkle weight="fill" /> DAILY CHECK-IN</p>
              <h1>开始今天的<br /><span>状态评估</span></h1>
              <p>填写三项基础信息，然后直接进入第一个小游戏。</p>
            </header>
            <div className="home-fields">
              <label><span>年龄</span><select value={profile.age} onChange={(e) => setProfile({ ...profile, age: e.target.value })}><option value="">请选择年龄</option><option>18-29 岁</option><option>30-44 岁</option><option>45-59 岁</option><option>60-69 岁</option><option>70 岁以上</option></select></label>
              <label><span>性别</span><select value={profile.gender} onChange={(e) => setProfile({ ...profile, gender: e.target.value })}><option value="">请选择性别</option><option>女</option><option>男</option><option>不便透露</option></select></label>
              <label><span>教育程度</span><select value={profile.education} onChange={(e) => setProfile({ ...profile, education: e.target.value })}><option value="">请选择教育程度</option><option>初中及以下</option><option>高中 / 中专</option><option>大专 / 本科</option><option>研究生及以上</option></select></label>
            </div>
            <div className="home-actions">
              <PrimaryButton disabled={!profile.age || !profile.gender || !profile.education} onClick={() => { resetAll(); openGame("symbol"); }}>开始评估 <ArrowRight weight="bold" /></PrimaryButton>
              <small><LockKey weight="bold" /> 匿名完成，信息仅用于本次结果</small>
            </div>
          </section>
          <p className="legal">结果仅供自我了解，不构成医疗诊断或治疗建议。</p>
        </main>
      )}

      {screen === "complete" && (
        <main className={`completion-screen completion-${completedGame}`}>
          <img className="completion-art" src={COMPLETION_IMAGES[completedGame]} alt="" />
          <p>{completedGameName}</p>
          <h1>本项游戏已结束</h1>
          <PrimaryButton onClick={continueFromCompletion}>
            {completionNext === "report" ? "查看结果" : "进入下一个游戏"} <ArrowRight weight="bold" />
          </PrimaryButton>
        </main>
      )}

      {screen === "profile" && (
        <main className="center-shell">
          <section className="profile-card">
            <button className="back-link" onClick={() => setScreen("home")}><ArrowLeft /> 返回首页</button>
            <div className="profile-grid">
              <div><p className="eyebrow">BEFORE WE START</p><h1>让报告更贴近你</h1><p>这些信息只用于解释本次表现，不需要姓名、手机号或账号。</p><div className="privacy-panel"><LockKey size={26} /><span><b>匿名完成</b><small>不会建立公开个人档案</small></span></div></div>
              <div className="form-panel">
                <label>年龄范围<select value={profile.age} onChange={(e) => setProfile({ ...profile, age: e.target.value })}><option value="">请选择</option><option>18-29 岁</option><option>30-44 岁</option><option>45-59 岁</option><option>60-69 岁</option><option>70 岁以上</option></select></label>
                <label>性别<select value={profile.gender} onChange={(e) => setProfile({ ...profile, gender: e.target.value })}><option value="">请选择</option><option>女</option><option>男</option><option>不便透露</option></select></label>
                <label>最高教育程度<select value={profile.education} onChange={(e) => setProfile({ ...profile, education: e.target.value })}><option value="">请选择</option><option>初中及以下</option><option>高中 / 中专</option><option>大专 / 本科</option><option>研究生及以上</option></select></label>
                <PrimaryButton disabled={!profile.age || !profile.gender || !profile.education} onClick={() => setScreen("overview")}>继续 <ArrowRight /></PrimaryButton>
              </div>
            </div>
          </section>
        </main>
      )}

      {screen === "overview" && (
        <main className="overview-shell">
          <nav><Brand /><span>测试准备</span></nav>
          <header><p className="eyebrow">YOUR ASSESSMENT</p><h1>五项任务，逐步完成</h1><p>每项开始前都有练习，不计入最终结果。</p></header>
          <section className="task-grid">
            {[
              { Icon: Speedometer, no: "01", title: "符号速配", domain: "处理速度", time: "60 秒", tone: "violet" },
              { Icon: Path, no: "02", title: "交替连线", domain: "执行功能", time: "180 秒", tone: "mint" },
              { Icon: Target, no: "03", title: "动态追踪", domain: "注意力", time: "60 秒", tone: "blue" },
              { Icon: SquaresFour, no: "04", title: "购物记忆", domain: "工作记忆", time: "180 秒", tone: "coral" },
              { Icon: ChartLineUp, no: "05", title: "零钱计算", domain: "计算能力", time: "约 2 分钟", tone: "blue" },
            ].map(({ Icon, no, title, domain, time, tone }) => (
              <article className={`task-card ${tone}`} key={no}><span>{no}</span><i><Icon size={34} weight="duotone" /></i><small>{domain}</small><h3>{title}</h3><b><ClockCountdown /> {time}</b></article>
            ))}
          </section>
          <div className="overview-action"><span><Heart weight="fill" /> 找一个安静的位置，保持浏览器全屏体验更佳。</span><PrimaryButton onClick={() => { resetAll(); openGame("symbol"); }}>进入第一项 <ArrowRight /></PrimaryButton></div>
        </main>
      )}

      {screen === "symbol" && (
        <main className={`game-shell symbol-shell ${intro === "symbol" ? "tutorial-active" : ""}`}>
          <GameHeader seconds={seconds} onBack={() => setExitConfirm(true)} />
          <section className="symbol-layout">
            <div className="target-zone"><div className="target-object" key={symbolTrial}><img src={SYMBOL_IMAGES[symbolTarget]} alt="" /></div></div>
            <div className="symbol-console">
              <LayoutGroup id="symbol-map"><div className="symbol-map">{symbolMap.map((symbol, number) => <div key={number} data-symbol={symbol}><b>{number}</b><motion.img layoutId={`symbol-${symbol}`} transition={{ type: "spring", stiffness: 240, damping: 25 }} src={SYMBOL_IMAGES[symbol]} alt="" /></div>)}</div></LayoutGroup>
              <div className="keypad">{[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].map((number) => <button data-number={number} key={number} onClick={() => answerSymbol(number)}>{number}</button>)}</div>
            </div>
          </section>
        </main>
      )}

      {screen === "trail" && (
        <main className={`game-shell trail-shell ${intro === "trail" ? "tutorial-active" : ""}`}>
          <GameHeader seconds={seconds} onBack={() => setExitConfirm(true)} />
          <section className="trail-board">
            <svg className="trail-lines" viewBox="0 0 100 100" preserveAspectRatio="none"><polyline points={trailPositions.slice(0, Math.max(1, intro === "trail" ? coachStep : trailIndex)).map((point) => `${point.x},${point.y}`).join(" ")} /></svg>
            {TRAIL_NODES.map((node, index) => {
              const position = trailPositions[index];
              const visibleIndex = intro === "trail" ? coachStep : trailIndex;
              return <button data-index={index} key={index} onClick={() => tapTrail(index)} className={`trail-node ${node.kind} ${index < visibleIndex ? "done" : ""} ${index === visibleIndex ? "current" : ""}`} style={{ left: `${position.x}%`, top: `${position.y}%`, "--slice": `${node.rank * 10}%` } as React.CSSProperties}>{node.kind === "number" ? node.rank : <span />}</button>;
            })}
          </section>
        </main>
      )}

      {screen === "attention" && (
        <main className={`game-shell attention-shell ${intro === "attention" ? "tutorial-active" : ""}`}>
          <GameHeader seconds={seconds} onBack={() => setExitConfirm(true)} />
          <section className="sky-stage">
            <div className="attention-title"><span>寻找目标颜色</span><strong className={targetColor}>{targetColor === "blue" ? "青绿色飞机" : "珊瑚色飞机"}</strong><small>{[0, 1, 2].map((life) => <Heart key={life} weight={life < attentionLives ? "fill" : "regular"} />)}</small></div>
            <div className="cloud cloud-a" /><div className="cloud cloud-b" />
            {intro === "attention"
              ? <img className={`coach-plane ${targetColor}`} src={PLANE_IMAGE[targetColor]} alt="教学目标飞机" style={{ "--angle": `${DIRECTION_ANGLE[attentionDirection]}deg` } as React.CSSProperties} />
              : planes.map((plane) => <img key={plane.id} className={`moving-plane ${plane.color} fly-${plane.direction}`} src={PLANE_IMAGE[plane.color]} alt={plane.target ? "目标飞机" : "干扰飞机"} style={{ "--lane": `${plane.lane}%`, "--angle": `${DIRECTION_ANGLE[plane.direction]}deg`, animationDuration: `${plane.duration}s`, animationDelay: `${plane.delay}s` } as React.CSSProperties} />)}
            <div className="direction-console">{DIRECTIONS.map((direction) => { const Icon = DIRECTION_ICONS[direction]; return <button data-direction={direction} className={`direction-${direction}`} key={direction} onClick={() => answerAttention(direction)} aria-label={DIRECTION_LABELS[direction]}><Icon weight="bold" /><span>{DIRECTION_LABELS[direction]}</span></button>; })}</div>
          </section>
        </main>
      )}

      {screen === "memory" && (
        <main className={`game-shell memory-shell ${intro === "memory" ? "tutorial-active" : ""}`}>
          <GameHeader seconds={seconds} onBack={() => setExitConfirm(true)} />
          {intro === "memory" && <section className={`market-stage memory-demo-stage ${listOpen ? "list-open" : ""}`}>
            <button className={`shopping-tab ${listOpen ? "open" : ""}`}><b>购物清单</b><span>{listOpen ? "收起" : "点击查看"}</span>{listOpen && <div className="shopping-list-preview">{memoryTargets.slice(0, 2).map((index) => <span key={index}><img src={FOODS[index].image} alt="" /></span>)}</div>}</button>
            {listOpen && <button className="market-list-shade" aria-label="收起购物清单" onClick={() => setListOpen(false)} />}
            <div className="conveyor memory-demo-belt"><div className="belt-lines" />{[...memoryTargets.slice(0, 2), ...beltOrder.filter((item) => !memoryTargets.slice(0, 2).includes(item)).slice(0, 1)].map((index) => { const item = FOODS[index]; return <button data-index={index} className="demo-belt-item" key={index} onClick={() => completeMemoryDemo(index)}><img src={item.image} alt={item.name} /></button>; })}</div>
          </section>}
          {intro !== "memory" && memoryPhase === "study" && <section className="study-stage"><div className="memory-study-copy"><p className="eyebrow">SHOPPING LIST · ROUND {memoryRound}</p><h2>记住需要购买的物品</h2><p>正式选择时回看清单会记录次数与停留时长，并影响工作记忆评分。</p></div><div className="memory-study-board"><header><b>第 {memoryRound} 轮</b><span>{memoryTargets.length} 件物品</span></header><div>{memoryTargets.map((index) => <img key={index} src={FOODS[index].image} alt="" />)}</div><PrimaryButton onClick={() => { setMemorySelected([]); setSeconds(MEMORY_ROUND_SECONDS[memoryRound]); setMemoryPhase("conveyor"); }}>我记好了 <ArrowRight /></PrimaryButton></div></section>}
          {intro !== "memory" && memoryPhase === "conveyor" && <section className={`market-stage ${listOpen ? "list-open" : ""}`}>
            <button className={`shopping-tab ${listOpen ? "open" : ""}`} onClick={toggleMemoryList}><b>购物清单</b><span>{listOpen ? "收起" : "回看会影响评分"}</span>{listOpen && <div className="shopping-list-preview">{memoryTargets.map((index) => { const selected = memorySelected.includes(index); return <span className={selected ? "selected" : ""} key={index}><img src={FOODS[index].image} alt="" />{selected && <i><Check weight="bold" /></i>}</span>; })}</div>}</button>
            {listOpen && <button className="market-list-shade" aria-label="收起购物清单" onClick={closeMemoryList} />}
            <div className="conveyor"><div className="belt-lines" />{beltOrder.map((index, order) => { if (memoryRetired.includes(index)) return null; const item = FOODS[index]; const selected = memorySelected.includes(index); return <button className={`belt-item ${item.tone} ${selected ? "selected" : ""}`} key={index} style={{ animationDelay: `${order * 3.5}s` }} onClick={(event) => selectMemoryItem(index, event.currentTarget)}><img src={item.image} alt={item.name} />{selected && <i><Check weight="bold" /></i>}</button>; })}</div>
          </section>}
        </main>
      )}

      {screen === "money" && (
        <main className={`game-shell money-shell ${intro === "money" ? "tutorial-active" : ""}`}>
          <GameHeader seconds={seconds} onBack={() => setExitConfirm(true)} />
          <section className={`change-stage ${intro === "money" ? "demo-change-stage" : ""}`}>
            <div className="change-summary"><p className="eyebrow">{intro === "money" ? "找零试玩" : `EXACT CHANGE · ROUND ${moneyRound} / ${MONEY_ROUNDS.length}`}</p><h2>组合正确的找零金额</h2><div><span>商品价格 <b>¥{intro === "money" ? 7 : moneyQuestion.price}</b></span><span>顾客付款 <b>¥{intro === "money" ? 10 : moneyQuestion.payment}</b></span></div><strong>{intro === "money" ? "应找零 ¥3.00" : "请自行计算应找金额"}</strong></div>
            <div className="cash-desk"><div className="cash-display"><span>当前已选</span><b>¥{cashTotal.toFixed(2)}</b><div>{cash.map((value, index) => <button data-cash-index={index} key={`${value}-${index}`} onClick={() => removeCash(index)} aria-label={`移除 ${value} 元`}><img src={moneyImage(value)} alt="" /><i className="cash-remove"><Minus weight="bold" /></i></button>)}</div></div><div className="money-pad">{MONEY_OPTIONS.map((option) => <button data-value={option.value} key={option.value} onClick={() => intro === "money" ? completeMoneyDemo(option.value) : setCash((items) => [...items, option.value])} aria-label={`${option.value} 元`}><img src={option.image} alt="" /></button>)}</div>{intro !== "money" && <PrimaryButton disabled={!cash.length} onClick={submitChange}>提交找零</PrimaryButton>}</div>
          </section>
        </main>
      )}

      {screen === "report" && (
        <main className="report-shell">
          <nav><Brand /><span className="report-chip"><Sparkle weight="fill" /> AI 表现报告</span></nav>
          <header className="report-hero"><div><p className="eyebrow">YOUR COGNITIVE SNAPSHOT</p><h1>本次综合表现</h1><p>以下结果结合准确率、完成度与错误情况生成。</p></div><img className="report-complete-art" src="/assets/ui/finish-all.png" alt="" /><div className="score-orb"><small>综合得分</small><strong>{overall}</strong><span>/100</span></div></header>
          <section className="report-facts"><span><small>完成度</small><b>{averageCompletion}%</b></span><span><small>正确操作</small><b>{totalCorrect}</b></span><span><small>错误操作</small><b>{totalErrors}</b></span></section>
          <section className="metric-grid">{reportRows.map(([key, label, Icon]) => { const metric = metrics[key]; const value = metric.score || 70; return <article key={key}><div><Icon weight="duotone" /><span><small>{label}</small><b>{value}</b></span></div><i><span style={{ width: `${value}%` }} /></i><div className="metric-data"><span><small>正确</small><b>{metric.correct}/{metric.total}</b></span><span><small>错误</small><b>{metric.errors}</b></span><span><small>完成</small><b>{metric.completion}%</b></span></div><p>{value >= 80 ? "表现稳定，速度和准确度配合较好。" : value >= 60 ? "整体平稳，仍有进一步提升空间。" : "波动较明显，建议休息后再尝试。"}</p></article>; })}</section>
          <section className="insight-panel"><div><img className="report-insight-art" src="/assets/ui/report-insight.png" alt="" /><span><small>AI 指标总结</small><h2>{overall >= 80 ? "整体状态稳定" : overall >= 60 ? "整体状态平稳" : "本次表现存在波动"}</h2></span></div><p>本次得分最高的维度是<strong>{strongestMetric}</strong>，相对需要关注的是<strong>{improvementMetric}</strong>。购物记忆正式阶段回看清单 <strong>{memoryListViews.current} 次</strong>、累计 <strong>{memoryReviewSeconds} 秒</strong>，已作为工作记忆评分的扣分因素；零钱计算单独统计，不再混入购物记忆。</p><div><span><Star weight="fill" /> 相对优势：{strongestMetric}</span><span><ChartLineUp /> 建议关注：{improvementMetric}</span></div></section>
          <div className="report-actions"><PrimaryButton secondary onClick={() => window.print()}>保存报告</PrimaryButton><PrimaryButton onClick={() => { resetAll(); openGame("symbol"); }}>重新评估 <ArrowRight /></PrimaryButton></div>
          <p className="legal">结果仅供自我了解与能力参考，不构成医疗或诊断建议。</p>
        </main>
      )}

      {feedback && <div className={`feedback-pop ${feedback}`} aria-label={feedback === "correct" ? "正确" : "错误"}>{feedback === "correct" ? <Check weight="bold" /> : <X weight="bold" />}</div>}
      {coach && <CoachOverlay target={coach.target} text={coach.text} onTargetClick={coach.onTargetClick} />}
      {intro && demoReady && <DemoReadyOverlay onStart={() => startGame(intro)} />}
      {exitConfirm && <div className="dialog-backdrop"><section className="dialog-card"><h2>退出当前任务？</h2><p>当前进度不会保留，你可以返回继续完成。</p><PrimaryButton onClick={() => setExitConfirm(false)}>继续测试</PrimaryButton><button onClick={() => { setExitConfirm(false); setIntro(null); setScreen("home"); }}>退出任务</button></section></div>}
    </div>
  );
}
