/* Game 3: Delivery Robot — drive, A = pick/drop (context), B = finish
   Game 4: Mergen — drive in shooting zone, A = shoot (joystick aims), B = reload stance
   UNIFIED CONTROLS: Joystick + A + B
*/

const { useState: useS3, useEffect: useE3, useRef: useR3, useMemo: useM3 } = React;

/* ========================================================
   DELIVERY ROBOT
   ======================================================== */
function GameDelivery({ game, onComplete }) {
  const [phase, setPhase] = useS3('tutorial');
  const [score, setScore] = useS3(0);
  const [breakdown, setBreakdown] = useS3([]);
  const [endStatus, setEndStatus] = useS3(null);
  const [carrying, setCarrying] = useS3(0);
  const [, force] = useS3(0);
  const finishRef = useR3(false);
  const stateRef = useR3(null);

  const W = 600, H = 400;
  const { robotRef, setInput, step: physStep, inputRef } = useRobot({ x: 60, y: 320, speed: 2.6 });

  const buildField = () => {
    const cells = [];
    for (let i = 0; i < 9; i++) {
      const col = i % 3, row = Math.floor(i / 3);
      cells.push({ id: i+1, x: 240 + col * 105, y: 60 + row * 105, can: false });
    }
    const idx = [...cells.keys()].sort(() => Math.random() - 0.5).slice(0, 4);
    idx.forEach(i => cells[i].can = true);
    const slots = [
      { id:'A', x: 90, y: 70, full: 0 },
      { id:'B', x: 90, y: 130, full: 0 },
      { id:'C', x: 90, y: 190, full: 0 },
      { id:'D', x: 90, y: 240, full: 0 },
      { id:'E', x: 90, y: 300, full: 0 },
      { id:'F', x: 90, y: 360, full: 0 },
    ];
    return { cells, slots };
  };

  const start = () => {
    stateRef.current = buildField();
    setCarrying(0); setScore(0); setBreakdown([]);
    robotRef.current.x = 60; robotRef.current.y = 320;
    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();

  // Find nearest can / nearest empty slot / finish
  const nearest = () => {
    if (!stateRef.current) return { kind: null };
    const r = robotRef.current;
    let cell = null, cd = 36;
    stateRef.current.cells.forEach(c => {
      if (!c.can) return;
      const d = Math.hypot(c.x - r.x, c.y - r.y);
      if (d < cd) { cd = d; cell = c; }
    });
    let slot = null, sd = 30;
    stateRef.current.slots.forEach(s => {
      if (s.full) return;
      const d = Math.hypot(s.x - r.x, s.y - r.y);
      if (d < sd) { sd = d; slot = s; }
    });
    const finishD = Math.hypot(70 - r.x, 360 - r.y);
    return { cell, slot, cd, sd, finishD, atFinish: finishD < 50 };
  };

  useE3(() => {
    if (phase !== 'playing' || !stateRef.current) return;
    let raf;
    const step = () => {
      physStep({ minX: 20, maxX: W-20, minY: 20, maxY: H-20 });
      force(t => t+1);
      raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [phase]);

  const onA = () => {
    if (phase !== 'playing') return;
    const n = nearest();
    if (carrying === 0 && n.cell) {
      n.cell.can = false;
      setCarrying(c => c + 1);
      showToast(t('toast.picked_can', { n: n.cell.id }));
    } else if (carrying > 0 && n.slot) {
      const award = n.sd < 16 ? 10 : 5;
      n.slot.full = 1;
      setCarrying(c => c - 1);
      setScore(sc => Math.min(50, sc + award));
      setBreakdown(b => [...b, { k: n.sd < 16 ? t('breakdown.can_in', { id: n.slot.id }) : t('breakdown.can_in_boundary', { id: n.slot.id }), v: award }]);
      showToast(`+${award}`);
    } else {
      showToast(carrying === 0 ? t('toast.no_can_nearby') : t('toast.no_slot_nearby'));
    }
  };

  const onB = () => {
    if (phase !== 'playing') return;
    const n = nearest();
    if (!n.atFinish) { showToast(t('toast.drive_finish')); return; }
    if (carrying > 0) { showToast(t('toast.drop_can_first')); return; }
    const filled = stateRef.current.slots.filter(s => s.full).length;
    if (filled >= 4) {
      setScore(s => Math.min(50, s + 10));
      setBreakdown(b => [...b, { k: t('breakdown.finish_start'), v: 10 }]);
    }
    end('finish');
  };

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

  if (!stateRef.current && phase !== 'tutorial') stateRef.current = buildField();
  const st = stateRef.current;
  const r = robotRef.current;
  const n = phase === 'playing' ? nearest() : {};
  const aLabel = carrying === 0 ? t('btn.pickup') : t('btn.drop');
  const aHint = carrying === 0
    ? (n.cell ? t('btn.hint_cell', { n: n.cell.id }) : t('btn.hint_find_can'))
    : (n.slot ? t('btn.hint_slot', { id: n.slot.id }) : t('btn.hint_find_slot'));
  const aActive = carrying === 0 ? !!n.cell : !!n.slot;

  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" />
          <rect x="20" y="20" width={W-40} height={H-40} fill="none" stroke="#1a1a1a" strokeWidth="2" rx="8" />

          <rect x="20" y="320" width="100" height="80" fill="oklch(0.88 0.17 95 / 0.25)" stroke="oklch(0.88 0.17 95)" strokeWidth="2" rx="6" />
          <text x="70" y="365" textAnchor="middle" fontSize="11" fontFamily="Space Mono" fill="#666" fontWeight={700}>FINISH</text>

          {st && st.slots.map(s => (
            <g key={s.id}>
              <rect x={s.x-20} y={s.y-20} width="40" height="40" rx="4"
                fill={s.full ? 'oklch(0.82 0.19 128 / 0.5)' : 'transparent'}
                stroke={n.slot?.id === s.id ? 'oklch(0.65 0.20 25)' : '#1a1a1a'}
                strokeWidth={n.slot?.id === s.id ? 3 : 2.5} strokeDasharray="3 3" />
              <text x={s.x} y={s.y+4} textAnchor="middle" fontSize="13" fontFamily="Space Mono" fontWeight={700} fill="#444">{s.id}</text>
              {s.full > 0 && <circle cx={s.x} cy={s.y} r="10" fill="#fbfaf7" stroke="#1a1a1a" strokeWidth="1.5" />}
            </g>
          ))}

          {st && st.cells.map(c => (
            <g key={c.id}>
              <circle cx={c.x} cy={c.y} r="26" fill="none"
                stroke={n.cell?.id === c.id ? 'oklch(0.65 0.20 25)' : '#1a1a1a'}
                strokeWidth={n.cell?.id === c.id ? 2.5 : 1.5}
                strokeDasharray="2 3" />
              <text x={c.x} y={c.y-32} textAnchor="middle" fontSize="10" fontFamily="Space Mono" fill="#888">{c.id}</text>
              {c.can && <g>
                <circle cx={c.x} cy={c.y} r="14" fill="#fbfaf7" stroke="#1a1a1a" strokeWidth="2" />
                <line x1={c.x-8} y1={c.y} x2={c.x+8} y2={c.y} stroke="#1a1a1a" strokeWidth="1" />
              </g>}
            </g>
          ))}

          <RobotSprite robot={r}
            carrying={carrying > 0 && (
              <circle cx="0" cy="-22" r="6" fill="#fbfaf7" stroke="#fff" strokeWidth="1.5" />
            )} />
        </svg>
      </div>

      <HUD time={time} score={score} status={t('hud.carrying')} extra={String(carrying)} />

      <div className="controls">
        <Joystick onChange={setInput} label={t('btn.steer')} />
        <ActionButtons
          aLabel={aLabel} aHint={aHint} onA={onA} aActive={aActive}
          bLabel={t('btn.finish')} bHint={t('btn.finish_hint')} onB={onB} bActive={n.atFinish && carrying === 0} />
      </div>

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

/* ========================================================
   MERGEN — drive shooter robot in shooting zone, A = shoot in driving direction
   Joystick aims AND moves. B = realign (snap to default aim).
   ======================================================== */
function GameMergen({ game, onComplete }) {
  const [phase, setPhase] = useS3('tutorial');
  const [score, setScore] = useS3(0);
  const [breakdown, setBreakdown] = useS3([]);
  const [balls, setBalls] = useS3(4);
  const [endStatus, setEndStatus] = useS3(null);
  const ballsInFlight = useR3([]);
  const targetsRef = useR3([]);
  const finishRef = useR3(false);
  const aimRef = useR3({ angle: 0, power: 0 });
  const [, force] = useS3(0);

  const W = 600, H = 380;
  const SHOOT_ZONE = { x: 50, y: 250, w: 150, h: 110 };
  const RIVER = { x: 230, y: 0, w: 80, h: H };

  const { robotRef, setInput, step: physStep, inputRef } = useRobot({
    x: SHOOT_ZONE.x + SHOOT_ZONE.w/2, y: SHOOT_ZONE.y + SHOOT_ZONE.h/2, speed: 2.0
  });

  const start = () => {
    const positions = [
      { x: 460, y: 80 }, { x: 460, y: 180 }, { x: 460, y: 280 },
      { x: 540, y: 130 }, { x: 540, y: 230 },
    ];
    const chosen = positions.sort(() => Math.random() - 0.5).slice(0, 3);
    targetsRef.current = chosen.map((p, i) => ({ ...p, id: i, down: false }));
    ballsInFlight.current = [];
    setBalls(4); setScore(0); setBreakdown([]);
    robotRef.current.x = SHOOT_ZONE.x + SHOOT_ZONE.w/2;
    robotRef.current.y = SHOOT_ZONE.y + SHOOT_ZONE.h/2;
    aimRef.current = { angle: 0, power: 0 };
    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();

  // Aim follows joystick direction; idle = face right
  useE3(() => {
    if (phase !== 'playing') return;
    let raf;
    const tick = () => {
      // Robot constrained inside shooting zone
      physStep({
        minX: SHOOT_ZONE.x + 16, maxX: SHOOT_ZONE.x + SHOOT_ZONE.w - 16,
        minY: SHOOT_ZONE.y + 16, maxY: SHOOT_ZONE.y + SHOOT_ZONE.h - 16,
      });
      // Aim direction tracks joystick if any input, else default to right (toward targets)
      const i = inputRef.current;
      const mag = Math.hypot(i.dx, i.dy);
      if (mag > 0.15) {
        aimRef.current.angle = Math.atan2(i.dy, i.dx);
      }

      // Update flying balls. The river is a visual obstacle only — in this 2D
      // sim balls fly horizontally so they can't "land" in it. Targets count
      // on direct hit.
      ballsInFlight.current = ballsInFlight.current.filter(b => {
        b.x += b.vx; b.y += b.vy;
        b.t += 1;
        if (b.x < 0 || b.x > W || b.y < 0 || b.y > H || b.t > 200) return false;
        for (const tg of targetsRef.current) {
          if (!tg.down && Math.hypot(tg.x - b.x, tg.y - b.y) < 18) {
            tg.down = true;
            setScore(s => s + 10);
            setBreakdown(br => [...br, { k: t('breakdown.target_down', { n: tg.id+1 }), v: 10 }]);
            const allDown = targetsRef.current.every(tt => tt.down);
            if (allDown) {
              setBalls(rem => {
                const bonus = rem * 5;
                if (bonus > 0) {
                  setScore(s => s + bonus);
                  setBreakdown(br => [...br, { k: rem === 1 ? t('breakdown.balls_unused', { n: rem }) : t('breakdown.balls_unused_p', { n: rem }), v: bonus }]);
                }
                return rem;
              });
              setScore(s => s + 5);
              setBreakdown(br => [...br, { k: t('breakdown.finish_bonus'), v: 5 }]);
              setTimeout(() => end('finish'), 600);
            }
            return false;
          }
        }
        return true;
      });

      // End the round once balls are spent and the last shot has resolved.
      // Without this the player sits in the field doing nothing until the 2:00
      // timeout fires — bad UX when you've burned all 4 with zero hits.
      if (balls <= 0 && ballsInFlight.current.length === 0 && !finishRef.current) {
        const allDown = targetsRef.current.every(tt => tt.down);
        if (!allDown) end('finish');
      }

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

  const onA = () => {
    if (phase !== 'playing' || balls <= 0) return;
    const r = robotRef.current;
    const a = aimRef.current.angle;
    const power = 12;
    ballsInFlight.current.push({
      x: r.x + Math.cos(a) * 18, y: r.y + Math.sin(a) * 18,
      vx: Math.cos(a) * power, vy: Math.sin(a) * power,
      t: 0, inRiver: false, checkedRiver: false,
    });
    setBalls(b => b - 1);
  };

  const onB = () => {
    // Snap aim to default (right, toward targets)
    aimRef.current.angle = 0;
    showToast(t('toast.aim_reset'));
  };

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

  const r = robotRef.current;
  const aimAngle = aimRef.current.angle;
  const aimEnd = { x: r.x + Math.cos(aimAngle) * 80, y: r.y + Math.sin(aimAngle) * 80 };

  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" />

          <rect x={RIVER.x} y={RIVER.y} width={RIVER.w} height={RIVER.h} fill="oklch(0.85 0.10 230 / 0.4)" />
          <line x1={RIVER.x} y1={0} x2={RIVER.x} y2={H} stroke="oklch(0.55 0.18 230)" strokeWidth="2" strokeDasharray="4 4" />
          <line x1={RIVER.x + RIVER.w} y1={0} x2={RIVER.x + RIVER.w} y2={H} stroke="oklch(0.55 0.18 230)" strokeWidth="2" strokeDasharray="4 4" />
          <text x={RIVER.x + RIVER.w/2} y={H/2} textAnchor="middle" fontSize="14" fontFamily="Space Mono" fill="#888" transform={`rotate(-90 ${RIVER.x+RIVER.w/2} ${H/2})`}>RIVER</text>

          <rect x={RIVER.x + RIVER.w} y={0} width="6" height={H} fill="oklch(0.88 0.17 95)" />

          <rect x={SHOOT_ZONE.x} y={SHOOT_ZONE.y} width={SHOOT_ZONE.w} height={SHOOT_ZONE.h}
            fill="oklch(0.82 0.19 128 / 0.2)" stroke="oklch(0.82 0.19 128)" strokeWidth="2" rx="6" />
          <text x={SHOOT_ZONE.x + SHOOT_ZONE.w/2} y={SHOOT_ZONE.y - 4} textAnchor="middle" fontSize="10" fontFamily="Space Mono" fill="#666" fontWeight={700}>SHOOTING ZONE</text>

          {targetsRef.current.map(t => (
            <g key={t.id} transform={`translate(${t.x},${t.y})`} opacity={t.down ? 0.3 : 1}>
              <rect x="-12" y="-4" width="24" height="6" fill="#444" />
              {!t.down && <rect x="-8" y="-30" width="16" height="28" rx="2" fill="#fbfaf7" stroke="#1a1a1a" strokeWidth="2" />}
              {t.down && <text x="0" y="0" textAnchor="middle" fontSize="20">✕</text>}
            </g>
          ))}

          {/* Aim line */}
          {phase === 'playing' && (
            <line x1={r.x} y1={r.y} x2={aimEnd.x} y2={aimEnd.y}
              stroke="oklch(0.65 0.20 25)" strokeWidth="2" strokeDasharray="3 3" pointerEvents="none" />
          )}

          {ballsInFlight.current.map((b, i) => (
            <circle key={i} cx={b.x} cy={b.y} r="6" fill="#fbfaf7" stroke="#1a1a1a" strokeWidth="2" />
          ))}

          {/* Robot with aim direction */}
          <g transform={`translate(${r.x},${r.y}) rotate(${aimAngle * 180 / Math.PI})`}>
            <rect x="-14" y="-10" width="28" height="20" rx="3" fill="#18171a" />
            <rect x="10" y="-3" width="14" height="6" fill="oklch(0.65 0.20 25)" />
            <circle cx="-4" cy="-3" r="2" fill="oklch(0.82 0.19 128)" />
            <circle cx="-4" cy="3" r="2" fill="oklch(0.82 0.19 128)" />
          </g>

          {/* Ball indicators */}
          {Array.from({length: balls}).map((_, i) => (
            <circle key={i} cx={SHOOT_ZONE.x + 18 + i*22} cy={SHOOT_ZONE.y + SHOOT_ZONE.h - 16} r="6" fill="#fbfaf7" stroke="#1a1a1a" strokeWidth="1.5" />
          ))}
        </svg>
      </div>

      <HUD time={time} score={score} status={t('hud.balls')} extra={String(balls)} />

      <div className="controls">
        <Joystick onChange={setInput} label={t('btn.steer_aim')} />
        <ActionButtons
          aLabel={t('btn.shoot')} aHint={t('btn.aim_hint_fire')} onA={onA} aDisabled={balls <= 0}
          bLabel={t('btn.aim_reset')} bHint={t('btn.aim_reset_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}
    </>
  );
}

window.GameDelivery = GameDelivery;
window.GameMergen = GameMergen;
