/* Game 5: Flag Delivery — drive across staged track, A = pick/drop, B = identify color
   Game 6: Sorting Robot — drive central robot, A = pick chip / drop on wall
   Game 7: RoboBasketball — drive, A = pick ball / shoot main basket, B = shoot side basket
   UNIFIED CONTROLS: Joystick + A + B
*/

const { useState: useS5, useEffect: useE5, useRef: useR5, useMemo: useM5 } = React;

/* ========================================================
   FLAG DELIVERY
   ======================================================== */
function GameFlag({ game, onComplete }) {
  const [phase, setPhase] = useS5('tutorial');
  const [score, setScore] = useS5(0);
  const [breakdown, setBreakdown] = useS5([]);
  const [endStatus, setEndStatus] = useS5(null);
  const [containerColor, setContainerColor] = useS5(null);
  const [containerSlot, setContainerSlot] = useS5(null);
  const [carryContainer, setCarryContainer] = useS5(false);
  const [containerDelivered, setContainerDelivered] = useS5(null); // 'B' or 'C'
  const [hasFlag, setHasFlag] = useS5(false);
  const [flagDelivered, setFlagDelivered] = useS5(false);
  const [zonesDone, setZonesDone] = useS5({}); // marks each obstacle visited
  const finishRef = useR5(false);
  const [, force] = useS5(0);

  const W = 600, H = 380;
  const { robotRef, setInput, step: physStep, inputRef } = useRobot({ x: 50, y: H/2, speed: 2.4 });

  // Track waypoint zones (centers + radii)
  const STAGES = useM5(() => ({
    start:    { x: 50,  y: H/2, r: 35, label: 'START' },
    zigzag:   { x: 155, y: H/2, r: 30, label: 'ZIGZAG', award: 10 },
    ramp:     { x: 270, y: H/2, r: 30, label: 'RAMP', award: 10 },
    gradient: { x: 350, y: H/2, r: 30, label: 'GRAD', award: 10 },
    inverse:  { x: 430, y: H/2, r: 30, label: 'INV', award: 10 },
    A1:       { x: 500, y: 120, r: 25, label: 'A1' },
    A2:       { x: 500, y: 260, r: 25, label: 'A2' },
    B:        { x: 565, y: 65,  r: 25, label: 'B (blue)' },
    C:        { x: 565, y: 315, r: 25, label: 'C (red)' },
    flag:     { x: 565, y: 190, r: 25, label: 'FLAG' },
  }), []);

  const start = () => {
    const color = Math.random() < 0.5 ? 'blue' : 'red';
    const slot = Math.random() < 0.5 ? 'A1' : 'A2';
    setContainerColor(color); setContainerSlot(slot);
    setCarryContainer(false); setContainerDelivered(null);
    setHasFlag(false); setFlagDelivered(false);
    setZonesDone({});
    setScore(0); setBreakdown([]);
    robotRef.current.x = 50; robotRef.current.y = H/2;
    finishRef.current = false;
    resetTime();
    setPhase('playing');
  };

  const [time, resetTime] = useTimer(game.duration, phase === 'playing', () => end('timeout'));
  useKeyboard((v) => { inputRef.current = v; });
  const [showToast, toastNode] = useToast();

  const award = (k, v) => {
    setScore(s => s + v);
    setBreakdown(b => [...b, { k, v }]);
    showToast(`${v >= 0 ? '+' : ''}${v} ${k}`);
  };

  const nearestStage = () => {
    const r = robotRef.current;
    let best = null, bd = Infinity;
    for (const k of Object.keys(STAGES)) {
      const z = STAGES[k];
      const d = Math.hypot(z.x - r.x, z.y - r.y);
      if (d < bd && d < z.r + 6) { bd = d; best = k; }
    }
    return best;
  };

  // Auto-award obstacle traversal as robot crosses through them
  useE5(() => {
    if (phase !== 'playing') return;
    let raf;
    const tick = () => {
      physStep({ minX: 20, maxX: W-20, minY: 20, maxY: H-20 });
      const r = robotRef.current;
      // Check if robot is inside any obstacle zone for the first time (forward direction)
      ['zigzag','ramp','gradient','inverse'].forEach(k => {
        const z = STAGES[k];
        const inside = Math.hypot(z.x - r.x, z.y - r.y) < z.r;
        setZonesDone(zd => {
          if (inside && !zd[k+'-fwd']) {
            award(t('breakdown.' + k + '_fwd'), 10);
            return { ...zd, [k+'-fwd']: true };
          }
          if (inside && zd['delivery-done'] && !zd[k+'-back']) {
            award(t('breakdown.' + k + '_back'), 10);
            return { ...zd, [k+'-back']: true };
          }
          return zd;
        });
      });
      force(t => t + 1);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [phase]);

  const onA = () => {
    if (phase !== 'playing') return;
    const r = robotRef.current;
    const near = nearestStage();
    // Pickup container
    if (!carryContainer && !containerDelivered && near === containerSlot) {
      setCarryContainer(true);
      award(t('breakdown.container_picked'), 0);
      return;
    }
    // Drop container at correct corridor
    if (carryContainer && (near === 'B' || near === 'C')) {
      setCarryContainer(false);
      const correct = (containerColor === 'blue' && near === 'B') || (containerColor === 'red' && near === 'C');
      if (correct) {
        award(t('breakdown.container_to', { dest: near }), 10);
        setContainerDelivered(near);
      } else {
        award(t('breakdown.wrong_corridor', { dest: near }), -5);
        setContainerDelivered('wrong');
      }
      return;
    }
    // Pick flag
    if (!hasFlag && containerDelivered && near === 'flag') {
      setHasFlag(true);
      award(t('breakdown.flag_picked'), 10);
      return;
    }
    // Drop flag at opposite corridor
    if (hasFlag && (near === 'B' || near === 'C')) {
      const opposite = containerDelivered === 'B' ? 'C' : 'B';
      setHasFlag(false);
      if (near === opposite) {
        award(t('breakdown.flag_correct'), 10);
        setFlagDelivered(true);
        setZonesDone(zd => ({ ...zd, 'delivery-done': true }));
      } else {
        award(t('breakdown.flag_wrong'), -5);
        setFlagDelivered(true);
        setZonesDone(zd => ({ ...zd, 'delivery-done': true }));
      }
      return;
    }
    // Finish
    if (near === 'start' && flagDelivered) {
      award(t('breakdown.finish_start'), 5);
      end('finish');
      return;
    }
    showToast(t('toast.nothing_to_do'));
  };

  // B button: in pickup phase, peek at color (no penalty, just highlights answer guidance)
  const onB = () => {
    if (phase !== 'playing') return;
    const near = nearestStage();
    if (near === containerSlot && !containerDelivered) {
      showToast(t('toast.container_is', { color: t('color.' + containerColor) }));
    } else if (carryContainer) {
      showToast(t('toast.carrying_color', { color: t('color.' + containerColor) }));
    } else if (hasFlag) {
      const door = containerDelivered === 'B' ? 'C (' + t('color.red') + ')' : 'B (' + t('color.blue') + ')';
      showToast(t('toast.return_via', { door }));
    } else {
      showToast(t('toast.identify_offline'));
    }
  };

  const end = (s) => {
    if (finishRef.current) return;
    finishRef.current = true;
    setEndStatus(s);
    setTimeout(() => setPhase('result'), 400);
  };

  const r = robotRef.current;
  const near = phase === 'playing' ? nearestStage() : null;

  // Build A-button context label
  let aLabel = t('btn.label_a'), aHint = '', aActive = false;
  if (!carryContainer && !containerDelivered && near === containerSlot) {
    aLabel = t('btn.pick_container'); aHint = t('btn.hint_at', { dest: containerSlot }); aActive = true;
  } else if (carryContainer && (near === 'B' || near === 'C')) {
    aLabel = t('btn.drop'); aHint = t('btn.hint_at', { dest: near }); aActive = true;
  } else if (!hasFlag && containerDelivered && near === 'flag') {
    aLabel = t('btn.pick_flag'); aHint = ''; aActive = true;
  } else if (hasFlag && (near === 'B' || near === 'C')) {
    aLabel = t('btn.drop_flag'); aHint = t('btn.hint_at', { dest: near }); aActive = true;
  } else if (near === 'start' && flagDelivered) {
    aLabel = t('btn.finish'); aHint = t('btn.finish_home'); aActive = true;
  } else {
    aLabel = carryContainer ? t('btn.drop') : (hasFlag ? t('btn.drop_flag') : t('btn.pickup'));
    aHint = t('btn.hint_drive');
  }

  return (
    <>
      <div className="field-wrap">
        <svg viewBox={`0 0 ${W} ${H}`} className="field" style={{width:'100%',maxHeight:'100%'}}>
          <rect width={W} height={H} fill="#fdfcf8" />
          <defs>
            <linearGradient id="grad-flag" x1="0%" y1="0%" x2="100%" y2="0%">
              <stop offset="0%" stopColor="#1a1a1a" />
              <stop offset="100%" stopColor="#fbfaf7" />
            </linearGradient>
          </defs>

          {/* Start */}
          <circle cx={STAGES.start.x} cy={STAGES.start.y} r={STAGES.start.r}
            fill="oklch(0.88 0.17 95 / 0.3)" stroke="oklch(0.88 0.17 95)" strokeWidth="2" />
          <text x={STAGES.start.x} y={STAGES.start.y - STAGES.start.r - 6} textAnchor="middle" fontSize="9" fontFamily="Space Mono" fill="#666">START</text>

          {/* Zigzag */}
          <g>
            <circle cx={STAGES.zigzag.x} cy={STAGES.zigzag.y} r={STAGES.zigzag.r} fill="none" stroke="#1a1a1a" strokeWidth="1" strokeDasharray="2 3" />
            <path d={`M ${STAGES.zigzag.x-22} ${STAGES.zigzag.y-10} L ${STAGES.zigzag.x-7} ${STAGES.zigzag.y+10} L ${STAGES.zigzag.x+7} ${STAGES.zigzag.y-10} L ${STAGES.zigzag.x+22} ${STAGES.zigzag.y+10}`} stroke="#1a1a1a" strokeWidth="3" fill="none" />
            <text x={STAGES.zigzag.x} y={STAGES.zigzag.y + 42} textAnchor="middle" fontSize="9" fontFamily="Space Mono" fill="#888">ZIGZAG</text>
          </g>

          {/* Ramp */}
          <rect x={STAGES.ramp.x-25} y={STAGES.ramp.y-25} width="50" height="50" fill="oklch(0.85 0.04 60)" stroke="#1a1a1a" strokeWidth="2" />
          <line x1={STAGES.ramp.x-25} y1={STAGES.ramp.y} x2={STAGES.ramp.x+25} y2={STAGES.ramp.y} stroke="#1a1a1a" strokeWidth="2" />
          <text x={STAGES.ramp.x} y={STAGES.ramp.y + 42} textAnchor="middle" fontSize="9" fontFamily="Space Mono" fill="#888">RAMP</text>

          {/* Gradient */}
          <rect x={STAGES.gradient.x-25} y={STAGES.gradient.y-25} width="50" height="50" fill="url(#grad-flag)" stroke="#1a1a1a" strokeWidth="2" />
          <text x={STAGES.gradient.x} y={STAGES.gradient.y + 42} textAnchor="middle" fontSize="9" fontFamily="Space Mono" fill="#888">GRADIENT</text>

          {/* Inverse */}
          <rect x={STAGES.inverse.x-25} y={STAGES.inverse.y-25} width="50" height="50" fill="#1a1a1a" />
          <line x1={STAGES.inverse.x-20} y1={STAGES.inverse.y} x2={STAGES.inverse.x+20} y2={STAGES.inverse.y} stroke="#fbfaf7" strokeWidth="3" />
          <text x={STAGES.inverse.x} y={STAGES.inverse.y + 42} textAnchor="middle" fontSize="9" fontFamily="Space Mono" fill="#888">INVERSE</text>

          {/* A1 / A2 pickup slots */}
          {['A1','A2'].map(slot => {
            const z = STAGES[slot];
            const isContainerHere = containerSlot === slot && !carryContainer && !containerDelivered;
            return (
              <g key={slot}>
                <rect x={z.x-22} y={z.y-22} width="44" height="44" rx="3"
                  fill={isContainerHere ? '#1a1a1a' : '#fff'}
                  stroke={near === slot ? 'oklch(0.65 0.20 25)' : '#1a1a1a'}
                  strokeWidth={near === slot ? 3 : 2} />
                <text x={z.x} y={z.y - 30} textAnchor="middle" fontSize="10" fontFamily="Space Mono" fontWeight={700}>{slot}</text>
                {isContainerHere && (
                  <rect x={z.x-12} y={z.y-12} width="24" height="24"
                    fill={containerColor === 'blue' ? '#3498db' : '#e74c3c'} />
                )}
              </g>
            );
          })}

          {/* B / C delivery zones */}
          <g>
            <rect x={STAGES.B.x-22} y={STAGES.B.y-22} width="44" height="44"
              fill="#3498db" opacity={containerDelivered === 'B' || flagDelivered ? 0.5 : 0.18}
              stroke={near === 'B' ? 'oklch(0.65 0.20 25)' : '#3498db'} strokeWidth={near === 'B' ? 3 : 2} />
            <text x={STAGES.B.x} y={STAGES.B.y + 4} textAnchor="middle" fontSize="13" fontFamily="Space Mono" fill="#1a4a6e" fontWeight={700}>B</text>
            <rect x={STAGES.C.x-22} y={STAGES.C.y-22} width="44" height="44"
              fill="#e74c3c" opacity={containerDelivered === 'C' || flagDelivered ? 0.5 : 0.18}
              stroke={near === 'C' ? 'oklch(0.65 0.20 25)' : '#e74c3c'} strokeWidth={near === 'C' ? 3 : 2} />
            <text x={STAGES.C.x} y={STAGES.C.y + 4} textAnchor="middle" fontSize="13" fontFamily="Space Mono" fill="#7e2418" fontWeight={700}>C</text>
          </g>

          {/* Flag zone */}
          <g>
            <circle cx={STAGES.flag.x} cy={STAGES.flag.y} r={STAGES.flag.r}
              fill="oklch(0.88 0.17 95 / 0.2)"
              stroke={near === 'flag' ? 'oklch(0.65 0.20 25)' : 'oklch(0.65 0.20 25 / 0.5)'}
              strokeWidth={near === 'flag' ? 3 : 2} strokeDasharray="3 3" />
            {!hasFlag && !flagDelivered && (
              <g transform={`translate(${STAGES.flag.x}, ${STAGES.flag.y})`}>
                <line x1="0" y1="-15" x2="0" y2="15" stroke="#1a1a1a" strokeWidth="2" />
                <path d="M 0 -15 L 14 -8 L 0 -1 Z" fill="oklch(0.65 0.20 25)" />
              </g>
            )}
          </g>

          <RobotSprite robot={r}
            carrying={
              <>
                {carryContainer && (
                  <rect x="-9" y="-26" width="18" height="14" rx="1"
                    fill={containerColor === 'blue' ? '#3498db' : '#e74c3c'}
                    stroke="#fff" strokeWidth="1.5" />
                )}
                {hasFlag && (
                  <g transform="translate(0,-22)">
                    <line x1="0" y1="-10" x2="0" y2="2" stroke="#fff" strokeWidth="1.5" />
                    <path d="M 0 -10 L 10 -5 L 0 0 Z" fill="oklch(0.65 0.20 25)" />
                  </g>
                )}
              </>
            } />
        </svg>
      </div>

      <HUD time={time} score={Math.max(0, score)} status={t('hud.cargo')}
        extra={carryContainer ? t('color.' + containerColor) : (hasFlag ? t('cargo.flag') : (flagDelivered ? t('cargo.returning') : t('cargo.empty')))} />

      <div className="controls">
        <Joystick onChange={setInput} label={t('btn.steer')} />
        <ActionButtons
          aLabel={aLabel} aHint={aHint} onA={onA} aActive={aActive}
          bLabel={t('btn.identify')} bHint={t('btn.identify_hint')} onB={onB} />
      </div>

      {phase === 'tutorial' && <TutorialOverlay game={game} onStart={start} onSkip={() => onComplete(0, 'skipped', false)} />}
      {phase === 'result' && (
        <ResultOverlay game={game} score={Math.max(0, score)} time={game.duration - time}
          breakdown={breakdown} status={endStatus}
          onRetry={() => setPhase('tutorial')}
          onNext={() => onComplete(Math.max(0, score), endStatus, true)}
          onSkip={() => onComplete(Math.max(0, score), endStatus, true, 'hub')} />
      )}
      {toastNode}
    </>
  );
}

/* ========================================================
   SORTING ROBOT — drive central robot to chips, A = pick chip / drop on wall
   ======================================================== */
function GameSorting({ game, onComplete }) {
  const [phase, setPhase] = useS5('tutorial');
  const [score, setScore] = useS5(0);
  const [breakdown, setBreakdown] = useS5([]);
  const [endStatus, setEndStatus] = useS5(null);
  const [carry, setCarry] = useS5(null); // chip color or null
  const finishRef = useR5(false);
  const [, force] = useS5(0);

  const COLORS = ['black','yellow','red','white','blue'];
  const COLOR_HEX = { black:'#18171a', yellow:'oklch(0.88 0.17 95)', red:'oklch(0.65 0.20 25)', white:'#fbfaf7', blue:'oklch(0.62 0.18 250)' };

  const W = 600, H = 400;
  const CX = W/2, CY = H/2, R = 140;

  const wallsRef = useR5([]);
  const chipsRef = useR5([]);
  const placedRef = useR5({}); // wall index -> chip color

  const { robotRef, setInput, step: physStep, inputRef } = useRobot({ x: CX, y: CY, speed: 2.2 });

  const setupRound = () => {
    const shuffled = [...COLORS].sort(() => Math.random() - 0.5);
    wallsRef.current = shuffled.map((c, i) => ({
      color: c,
      angle: (i / 5) * Math.PI * 2 - Math.PI / 2,
    }));
    // Chips strewn inside the ring at random positions
    chipsRef.current = COLORS.map((c, i) => {
      const a = Math.random() * Math.PI * 2;
      const rad = 30 + Math.random() * (R - 70);
      return {
        color: c, picked: false, placed: null,
        x: CX + Math.cos(a) * rad,
        y: CY + Math.sin(a) * rad,
      };
    });
    placedRef.current = {};
    robotRef.current.x = CX;
    robotRef.current.y = CY;
  };

  const start = () => {
    setupRound();
    setCarry(null); setScore(0); setBreakdown([]);
    finishRef.current = false;
    resetTime();
    setPhase('playing');
  };

  const [time, resetTime] = useTimer(game.duration, phase === 'playing', () => end('timeout'));
  useKeyboard((v) => { inputRef.current = v; });
  const [showToast, toastNode] = useToast();

  const wallSlot = (i) => {
    const w = wallsRef.current[i];
    return {
      i,
      x: CX + Math.cos(w.angle) * (R - 30),
      y: CY + Math.sin(w.angle) * (R - 30),
      color: w.color,
    };
  };

  // Find nearest unplaced chip / nearest unfilled wall
  const nearest = () => {
    const r = robotRef.current;
    let chip = null, cd = 26;
    chipsRef.current.forEach(c => {
      if (c.picked || c.placed != null) return;
      const d = Math.hypot(c.x - r.x, c.y - r.y);
      if (d < cd) { cd = d; chip = c; }
    });
    let wall = null, wd = 36;
    wallsRef.current.forEach((w, i) => {
      if (placedRef.current[i]) return;
      const s = wallSlot(i);
      const d = Math.hypot(s.x - r.x, s.y - r.y);
      if (d < wd) { wd = d; wall = { ...s, dist: d }; }
    });
    return { chip, wall };
  };

  useE5(() => {
    if (phase !== 'playing') return;
    let raf;
    const loop = () => {
      // Bound robot inside the ring
      physStep({});
      const r = robotRef.current;
      const dx = r.x - CX, dy = r.y - CY;
      const d = Math.hypot(dx, dy);
      if (d > R - 18) {
        r.x = CX + dx / d * (R - 18);
        r.y = CY + dy / d * (R - 18);
      }
      force(t => t + 1);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [phase]);

  const onA = () => {
    if (phase !== 'playing') return;
    const n = nearest();
    if (!carry && n.chip) {
      n.chip.picked = true;
      setCarry(n.chip);
      showToast(t('toast.picked_color', { color: t('color.' + n.chip.color) }));
    } else if (carry && n.wall) {
      const correct = n.wall.color === carry.color;
      const onBoundary = n.wall.dist > 22;
      let pts = 0, label = '';
      const colorName = t('color.' + carry.color);
      if (correct && !onBoundary) { pts = 10; label = t('breakdown.chip_placed', { color: colorName }); }
      else if (correct && onBoundary) { pts = 5; label = t('breakdown.chip_boundary', { color: colorName }); }
      else { pts = -5; label = t('breakdown.chip_wrong', { color: colorName }); }
      setScore(s => s + pts);
      setBreakdown(b => [...b, { k: label, v: pts }]);
      // Move chip to wall slot
      const chip = chipsRef.current.find(c => c.color === carry.color);
      chip.placed = n.wall.i;
      chip.x = n.wall.x; chip.y = n.wall.y;
      placedRef.current[n.wall.i] = carry.color;
      setCarry(null);
      showToast(`${pts >= 0 ? '+' : ''}${pts}`);
      // Check completion
      if (chipsRef.current.every(c => c.placed != null)) {
        setTimeout(() => end('finish'), 300);
      }
    } else {
      showToast(carry ? t('toast.no_wall_nearby') : t('toast.no_chip_nearby'));
    }
  };

  const end = (s) => {
    if (finishRef.current) return;
    finishRef.current = true;
    setEndStatus(s);
    setTimeout(() => setPhase('result'), 400);
  };

  const r = robotRef.current;
  const n = phase === 'playing' ? nearest() : {};
  const placed = chipsRef.current.filter(c => c.placed != null).length;

  return (
    <>
      <div className="field-wrap">
        <svg viewBox={`0 0 ${W} ${H}`} className="field" style={{width:'100%',maxHeight:'100%'}}>
          <rect width={W} height={H} fill="#fdfcf8" />
          <circle cx={CX} cy={CY} r={R} fill="#fbfaf7" stroke="#18171a" strokeWidth="3" />

          {wallsRef.current.map((w, i) => {
            const wx = CX + Math.cos(w.angle) * R;
            const wy = CY + Math.sin(w.angle) * R;
            const sx = CX + Math.cos(w.angle) * (R - 30);
            const sy = CY + Math.sin(w.angle) * (R - 30);
            const filled = placedRef.current[i];
            const isNear = n.wall?.i === i;
            return (
              <g key={i}>
                <rect x={wx-14} y={wy-26} width="28" height="50"
                  transform={`rotate(${w.angle * 180 / Math.PI + 90} ${wx} ${wy})`}
                  fill={COLOR_HEX[w.color]} stroke={w.color === 'white' ? '#1a1a1a' : 'none'} strokeWidth="1.5" />
                <circle cx={sx} cy={sy} r="22" fill="none"
                  stroke={isNear ? 'oklch(0.65 0.20 25)' : '#1a1a1a'}
                  strokeWidth={isNear ? 3 : 1.5} strokeDasharray="3 3" />
                {filled && (
                  <rect x={sx-9} y={sy-9} width="18" height="18" rx="2"
                    fill={COLOR_HEX[filled]} stroke="#1a1a1a" strokeWidth="1" />
                )}
              </g>
            );
          })}

          {/* Chips on field */}
          {chipsRef.current.map((c, i) => {
            if (c.placed != null) return null;
            if (c.picked && carry?.color === c.color) return null;
            const isNear = n.chip?.color === c.color;
            return (
              <g key={i}>
                <rect x={c.x-11} y={c.y-11} width="22" height="22" rx="3"
                  fill={COLOR_HEX[c.color]}
                  stroke={isNear ? 'oklch(0.65 0.20 25)' : '#1a1a1a'}
                  strokeWidth={isNear ? 2.5 : 1.5} />
              </g>
            );
          })}

          {/* Robot */}
          <RobotSprite robot={r} color="#18171a"
            carrying={carry && (
              <rect x="-9" y="-26" width="18" height="14" rx="2"
                fill={COLOR_HEX[carry.color]} stroke="#fff" strokeWidth="1.5" />
            )} />
        </svg>
      </div>

      <HUD time={time} score={score} status={t('hud.placed')} extra={`${placed}/5`} />

      <div className="controls">
        <Joystick onChange={setInput} label={t('btn.steer')} />
        <ActionButtons
          aLabel={carry ? t('btn.drop') : t('btn.pick_chip')}
          aHint={carry
            ? (n.wall ? t('btn.hint_color_wall', { color: t('color.' + n.wall.color) }) : t('btn.hint_find_wall'))
            : (n.chip ? t('color.' + n.chip.color) : t('btn.hint_find_chip'))}
          onA={onA}
          aActive={carry ? !!n.wall : !!n.chip} />
      </div>

      {phase === 'tutorial' && <TutorialOverlay game={game} onStart={start} onSkip={() => onComplete(0, 'skipped', false)} />}
      {phase === 'result' && (
        <ResultOverlay game={game} score={Math.max(0, score)} time={game.duration - time}
          breakdown={breakdown} status={endStatus}
          onRetry={() => setPhase('tutorial')}
          onNext={() => onComplete(Math.max(0, score), endStatus, true)}
          onSkip={() => onComplete(Math.max(0, score), endStatus, true, 'hub')} />
      )}
      {toastNode}
    </>
  );
}

/* ========================================================
   ROBOBASKETBALL
   ======================================================== */
function GameBasketball({ game, onComplete }) {
  const [phase, setPhase] = useS5('tutorial');
  const [score, setScore] = useS5(0);
  const [oppScore, setOppScore] = useS5(0);
  const [breakdown, setBreakdown] = useS5([]);
  const [endStatus, setEndStatus] = useS5(null);
  const [hasBall, setHasBall] = useS5(0);
  const oppRef = useR5({ x: 470, y: 200, vx:0, vy:0, hasBall:0, target:null });
  const ballsRef = useR5([]);
  const flightRef = useR5([]);
  const finishRef = useR5(false);
  const [, force] = useS5(0);

  const W = 600, H = 380;
  const RED_LINE = W/2;

  const { robotRef, setInput, step: physStep, inputRef } = useRobot({ x: 130, y: H/2, speed: 2.6 });

  const BASKETS = {
    leftMain:  { x: 30,    y: H/2 - 50, w: 24, h: 50, side:'mine', kind:'main', val: 3 },
    leftSide:  { x: 30,    y: H/2 + 60, w: 24, h: 30, side:'mine', kind:'side', val: 1 },
    rightMain: { x: W-54,  y: H/2 - 50, w: 24, h: 50, side:'opp',  kind:'main', val: 3 },
    rightSide: { x: W-54,  y: H/2 + 60, w: 24, h: 30, side:'opp',  kind:'side', val: 1 },
  };

  const start = () => {
    const positions = [];
    for (let s = 0; s < 2; s++) {
      const baseX = s === 0 ? 130 : 470;
      const offsets = [
        {x: 0, y: -60}, {x: -60, y: 0}, {x: 60, y: 0}, {x: 0, y: 60}
      ].sort(() => Math.random()-0.5).slice(0,4);
      offsets.forEach(o => positions.push({ x: baseX + o.x, y: H/2 + o.y, side: s===0?'mine':'opp', held: false }));
    }
    ballsRef.current = positions;
    flightRef.current = [];
    robotRef.current.x = 130; robotRef.current.y = H/2;
    oppRef.current = { x: 470, y: H/2, vx:0, vy:0, hasBall:0, target:null };
    setScore(0); setOppScore(0); setBreakdown([]);
    setHasBall(0);
    finishRef.current = false;
    resetTime();
    setPhase('playing');
  };

  const [time, resetTime] = useTimer(game.duration, phase === 'playing', () => endMatch('timeout'));
  useKeyboard((v) => { inputRef.current = v; });
  const [showToast, toastNode] = useToast();

  const shoot = (basketKey) => {
    if (phase !== 'playing') return;
    if (hasBall < 1) { showToast(t('toast.no_ball')); return; }
    const r = robotRef.current;
    const b = BASKETS[basketKey];
    const tx = b.x + b.w/2, ty = b.y + b.h/2;
    const dx = tx - r.x, dy = ty - r.y;
    const d = Math.hypot(dx, dy);
    const accuracy = Math.max(0.4, 1 - d / 600);
    const success = Math.random() < accuracy;
    flightRef.current.push({
      x: r.x, y: r.y,
      vx: dx / 30, vy: dy / 30,
      target: basketKey, scored: success, owner: 'mine', t: 0,
    });
    setHasBall(b => b - 1);
  };

  const onA = () => shoot('rightMain');
  const onB = () => shoot('rightSide');

  useE5(() => {
    if (phase !== 'playing') return;
    let raf;
    const tick = () => {
      // Player physics — bounded to my half
      physStep({ minX: 20, maxX: RED_LINE - 18, minY: 20, maxY: H-20 });
      const r = robotRef.current;
      const o = oppRef.current;

      // Pickup balls in my half
      ballsRef.current.forEach(b => {
        if (!b.held && b.side === 'mine' && Math.hypot(b.x - r.x, b.y - r.y) < 24) {
          setHasBall(prev => {
            if (prev < 2) { b.held = 'me'; return prev + 1; }
            return prev;
          });
        }
      });

      // Opponent AI
      if (!o.target) {
        const targets = ballsRef.current.filter(b => !b.held && b.side === 'opp');
        if (targets.length) o.target = targets[Math.floor(Math.random()*targets.length)];
      }
      if (o.target) {
        const tx = o.target.x, ty = o.target.y;
        o.vx += ((tx - o.x) * 0.04 - o.vx) * 0.2;
        o.vy += ((ty - o.y) * 0.04 - o.vy) * 0.2;
        o.x += o.vx; o.y += o.vy;
        o.x = Math.max(RED_LINE + 18, Math.min(W-20, o.x));
        if (Math.hypot(o.x - tx, o.y - ty) < 22) {
          o.target.held = 'opp'; o.hasBall += 1; o.target = null;
        }
      }
      if (o.hasBall > 0 && Math.random() < 0.012) {
        const b = Math.random() < 0.5 ? BASKETS.leftMain : BASKETS.leftSide;
        const dx = b.x - o.x, dy = b.y - o.y;
        const d = Math.hypot(dx,dy);
        const acc = Math.max(0.3, 1 - d/700);
        flightRef.current.push({
          x: o.x, y: o.y,
          vx: dx/40, vy: dy/40,
          target: b === BASKETS.leftMain ? 'leftMain' : 'leftSide',
          scored: Math.random() < acc,
          owner: 'opp', t: 0,
        });
        o.hasBall -= 1;
      }

      flightRef.current = flightRef.current.filter(f => {
        f.x += f.vx; f.y += f.vy; f.t++;
        const b = BASKETS[f.target];
        const dx = b.x + b.w/2 - f.x, dy = b.y + b.h/2 - f.y;
        if (Math.hypot(dx,dy) < 14) {
          if (f.scored) {
            if (f.owner === 'mine') {
              setScore(s => s + b.val);
              setBreakdown(br => [...br, { k: t('breakdown.' + b.kind + '_basket'), v: b.val }]);
              showToast(`+${b.val}`);
            } else {
              setOppScore(s => s + b.val);
            }
          }
          return false;
        }
        return f.t < 60;
      });

      force(t => t+1);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [phase]);

  const endMatch = (s) => {
    if (finishRef.current) return;
    finishRef.current = true;
    if (score > oppScore) {
      setBreakdown(b => [...b, { k: t('breakdown.win_bonus'), v: 5 }]);
      setScore(sc => sc + 5);
    }
    setEndStatus(s);
    setTimeout(() => setPhase('result'), 400);
  };

  const r = robotRef.current, o = oppRef.current;

  return (
    <>
      <div className="field-wrap">
        <svg viewBox={`0 0 ${W} ${H}`} className="field" style={{width:'100%',maxHeight:'100%'}}>
          <rect width={W} height={H} fill="#fbfaf7" />
          <rect width={W} height={H} fill="oklch(0.85 0.04 60 / 0.3)" />
          <line x1={RED_LINE} y1={20} x2={RED_LINE} y2={H-20} stroke="oklch(0.65 0.20 25)" strokeWidth="6" />
          <text x={W*0.25} y="20" textAnchor="middle" fontSize="10" fontFamily="Space Mono" fill="#888">YOUR HALF</text>
          <text x={W*0.75} y="20" textAnchor="middle" fontSize="10" fontFamily="Space Mono" fill="#888">OPPONENT</text>

          {Object.entries(BASKETS).map(([key, b]) => (
            <g key={key}>
              <rect x={b.x} y={b.y} width={b.w} height={b.h} rx="3"
                fill={b.side === 'opp' ? 'oklch(0.82 0.19 128 / 0.3)' : 'oklch(0.65 0.20 25 / 0.15)'}
                stroke={b.side === 'opp' ? 'oklch(0.82 0.19 128)' : 'oklch(0.65 0.20 25)'} strokeWidth="2" />
              <text x={b.x + b.w/2} y={b.y + b.h/2 + 4} textAnchor="middle" fontSize="10" fontFamily="Space Mono" fontWeight={700}>
                {b.val}pt
              </text>
            </g>
          ))}

          {ballsRef.current.filter(b => !b.held).map((b, i) => (
            <circle key={i} cx={b.x} cy={b.y} r="6" fill="oklch(0.78 0.18 60)" stroke="#1a1a1a" strokeWidth="1" />
          ))}

          {flightRef.current.map((f, i) => (
            <circle key={i} cx={f.x} cy={f.y} r="5" fill="oklch(0.78 0.18 60)" />
          ))}

          <RobotSprite robot={r}
            carrying={hasBall > 0 && (
              <circle cx="0" cy="-18" r="5" fill="oklch(0.78 0.18 60)" stroke="#fff" strokeWidth="1.5" />
            )} />

          <g transform={`translate(${o.x},${o.y})`}>
            <rect x="-14" y="-10" width="28" height="20" rx="3" fill="oklch(0.45 0.10 25)" />
            <circle cx="-5" cy="-2" r="2" fill="#fff" />
            <circle cx="5" cy="-2" r="2" fill="#fff" />
            {o.hasBall > 0 && <circle cx="0" cy="-16" r="5" fill="oklch(0.78 0.18 60)" stroke="#1a1a1a" strokeWidth="1" />}
          </g>
        </svg>
      </div>

      <HUD time={time} score={score} status={t('hud.vs_opp')} extra={`${score}–${oppScore}`} />

      <div className="controls">
        <Joystick onChange={setInput} label={t('btn.steer')} />
        <ActionButtons
          aLabel={t('btn.main_basket')}
          aHint={hasBall === 1 ? t('btn.hint_balls_n', { n: hasBall }) : t('btn.hint_balls_p', { n: hasBall })}
          onA={onA} aDisabled={hasBall < 1}
          bLabel={t('btn.side_basket')} bHint="" onB={onB} bDisabled={hasBall < 1} />
      </div>

      {phase === 'tutorial' && <TutorialOverlay game={game} onStart={start} onSkip={() => onComplete(0, 'skipped', false)} />}
      {phase === 'result' && (
        <ResultOverlay game={game} score={Math.max(0, score)} time={game.duration - time}
          breakdown={[...breakdown, { k: t('result.opp_scored'), v: -oppScore }]} status={endStatus}
          onRetry={() => setPhase('tutorial')}
          onNext={() => onComplete(Math.max(0, score), endStatus, true)}
          onSkip={() => onComplete(Math.max(0, score), endStatus, true, 'hub')} />
      )}
      {toastNode}
    </>
  );
}

window.GameFlag = GameFlag;
window.GameSorting = GameSorting;
window.GameBasketball = GameBasketball;
