/* Shared UI: HUD, Tutorial overlay, Result screen, Joystick, GameShell wrapper */

const { useState, useEffect, useRef, useCallback, useMemo } = React;

function useTimer(durationS, running, onTimeout) {
  const [remaining, setRemaining] = useState(durationS);
  const startRef = useRef(null);
  const rafRef = useRef(null);
  const timeoutCalled = useRef(false);

  useEffect(() => {
    if (!running) {
      startRef.current = null;
      cancelAnimationFrame(rafRef.current);
      return;
    }
    timeoutCalled.current = false;
    startRef.current = performance.now();
    const initial = remaining;
    const tick = () => {
      const elapsed = (performance.now() - startRef.current) / 1000;
      const r = Math.max(0, initial - elapsed);
      setRemaining(r);
      if (r <= 0) {
        if (!timeoutCalled.current) {
          timeoutCalled.current = true;
          onTimeout && onTimeout();
        }
        return;
      }
      rafRef.current = requestAnimationFrame(tick);
    };
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
  // eslint-disable-next-line
  }, [running]);

  const reset = useCallback(() => {
    setRemaining(durationS);
    timeoutCalled.current = false;
  }, [durationS]);

  return [remaining, reset];
}

function HUD({ time, totalTime, score, status, extra }) {
  useLocale();
  const lowTime = time < 10;
  return (
    <div className="hud">
      <div className="hud-stat">
        <div className="lbl">{t('hud.score')}</div>
        <div className="val">{score}</div>
      </div>
      <div className="hud-stat center">
        <div className="lbl">{status || t('hud.status')}</div>
        <div className="val">{extra ?? '—'}</div>
      </div>
      <div className="hud-stat right">
        <div className="lbl">{t('hud.time')}</div>
        <div className={`val${lowTime ? ' warn' : ''}`} style={{fontVariantNumeric:'tabular-nums'}}>{fmtTime(time)}</div>
      </div>
    </div>
  );
}

function GameHeader({ game, onClose }) {
  useLocale();
  return (
    <div className="game-header">
      <button className="icon-btn" onClick={onClose} aria-label="Back">
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
      </button>
      <div className="game-title-block">
        <div className="cat">{`Level ${game.num} · ${game.age}`}</div>
        <div className="nm">{game.name}</div>
      </div>
      <div className="icon-btn" style={{background:'transparent',border:'none'}} aria-hidden>
        <RobotGlyph color="currentColor" size={22} variant={parseInt(game.num)} />
      </div>
    </div>
  );
}

function NamePromptOverlay({ initialName = '', onSave, onCancel }) {
  useLocale();
  // First-visit default: an auto-generated Guest-NNNN. Held in a ref so it
  // doesn't change every keystroke, only when the overlay first mounts.
  const defaultRef = useRef(initialName || (window.generateGuestName ? window.generateGuestName() : 'Guest-0001'));
  const [value, setValue] = useState(defaultRef.current);
  const [error, setError] = useState(null);
  const inputRef = useRef(null);
  useEffect(() => {
    inputRef.current?.focus();
    inputRef.current?.select();
  }, []);
  const submit = () => {
    const v = value.trim();
    if (v.length < 2) { setError(t('profile.invalid')); return; }
    onSave(v);
  };
  return (
    <div className="overlay">
      <div className="overlay-card">
        <h2 style={{marginBottom: 8}}>{t('profile.welcome_title')}</h2>
        <p>{t('profile.welcome_blurb')}</p>
        <input
          ref={inputRef}
          className="name-input"
          type="text"
          maxLength={32}
          value={value}
          onChange={(e) => { setValue(e.target.value); if (error) setError(null); }}
          onKeyDown={(e) => { if (e.key === 'Enter') submit(); }}
          placeholder={t('profile.placeholder')}
        />
        {error && <div className="form-error">{error}</div>}
        <div style={{height: 12}} />
        <button className="btn-primary" onClick={submit}>{t('profile.save')}</button>
        {onCancel && <button className="btn-secondary" onClick={onCancel}>{t('profile.cancel')}</button>}
      </div>
    </div>
  );
}

function TutorialOverlay({ game, onStart, isRetry, onSkip }) {
  useLocale();
  return (
    <div className="overlay">
      <div className="overlay-card">
        <div className="eyebrow">{t('tut.eyebrow', { n: game.duration / 60 })}</div>
        <h2>{game.name}</h2>
        <p>{game.blurb}</p>
        <div className="tut-steps">
          {game.tutorial.map((s, i) => (
            <div className="tut-step" key={i}>
              <div className="n">{i+1}</div>
              <div className="t">{s.t}</div>
            </div>
          ))}
        </div>
        <div className="scoring-table">
          {game.scoring.map((r, i) => (
            <div className="scoring-row" key={i}>
              <div>{r.k}</div>
              <div className={`pts ${r.kind}`}>{r.v}</div>
            </div>
          ))}
        </div>
        <button className="btn-primary" onClick={onStart}>
          {isRetry ? t('tut.retry') : t('tut.start')}
        </button>
        {onSkip && (
          <button className="btn-secondary" onClick={onSkip}>{t('tut.skip')}</button>
        )}
      </div>
    </div>
  );
}

function ResultOverlay({ game, score, time, breakdown, status, onRetry, onNext, isLast, savedAsBest, onSkip }) {
  useLocale();
  const win = score >= game.maxScore * 0.6;
  const headline = status === 'timeout' ? t('result.timeout')
    : status === 'dq' ? t('result.dq')
    : t('result.complete');
  const sub = status === 'timeout' ? t('result.timeout_sub')
    : status === 'dq' ? t('result.dq_sub')
    : t('result.finish_sub', { time: fmtTime(time) });

  return (
    <div className="overlay">
      <div className="overlay-card result">
        <div className="result-ribbon">{t('result.ribbon', { name: game.name })}</div>
        <div className={`result-score${win ? ' win' : ''}`}>{score}</div>
        <div className="result-headline">{headline}</div>
        <div className="result-sub">{sub} {t('result.max_suffix', { n: game.maxScore })}</div>
        {savedAsBest && <div className="chip" style={{marginBottom: 14, background: 'var(--accent)', borderColor: 'transparent'}}>{t('result.best_chip')}</div>}
        {breakdown && breakdown.length > 0 && (
          <div className="result-breakdown">
            {breakdown.map((r, i) => (
              <div className="row" key={i}>
                <span>{r.k}</span>
                <span style={{color: r.v < 0 ? 'var(--signal)' : 'inherit'}}>{r.v >= 0 ? '+' : ''}{r.v}</span>
              </div>
            ))}
            <div className="row total">
              <span>{t('result.total')}</span>
              <span>{score}</span>
            </div>
          </div>
        )}
        <button className="btn-primary" onClick={onNext} disabled={isLast}>
          {isLast ? t('result.last') : t('result.next')}
        </button>
        <button className="btn-secondary" onClick={onRetry}>{t('result.retry')}</button>
        {onSkip && (
          <button className="btn-secondary" onClick={onSkip} style={{marginTop: 0}}>{t('result.skip_hub')}</button>
        )}
      </div>
    </div>
  );
}

/* Virtual joystick — emits {dx, dy} normalized [-1..1] */
function Joystick({ onChange, label = 'Steer' }) {
  const baseRef = useRef(null);
  const [knob, setKnob] = useState({ x: 0, y: 0 });
  const activeRef = useRef(null);

  const set = (cx, cy) => {
    const r = baseRef.current.getBoundingClientRect();
    const ox = r.left + r.width / 2;
    const oy = r.top + r.height / 2;
    let dx = cx - ox;
    let dy = cy - oy;
    const max = r.width / 2 - 14;
    const len = Math.hypot(dx, dy);
    if (len > max) { dx = dx / len * max; dy = dy / len * max; }
    setKnob({ x: dx, y: dy });
    onChange && onChange({ dx: dx / max, dy: dy / max });
  };
  const release = () => {
    setKnob({ x: 0, y: 0 });
    activeRef.current = null;
    onChange && onChange({ dx: 0, dy: 0 });
  };

  useEffect(() => {
    const el = baseRef.current;
    if (!el) return;
    const start = (e) => {
      e.preventDefault();
      const t = e.touches ? e.touches[0] : e;
      activeRef.current = e.touches ? t.identifier : 'mouse';
      set(t.clientX, t.clientY);
    };
    const move = (e) => {
      if (activeRef.current == null) return;
      const t = e.touches ? Array.from(e.touches).find(x => x.identifier === activeRef.current) || e.touches[0] : e;
      if (!t) return;
      set(t.clientX, t.clientY);
    };
    const end = (e) => { release(); };
    el.addEventListener('touchstart', start, { passive: false });
    window.addEventListener('touchmove', move, { passive: false });
    window.addEventListener('touchend', end);
    el.addEventListener('mousedown', start);
    window.addEventListener('mousemove', move);
    window.addEventListener('mouseup', end);
    return () => {
      el.removeEventListener('touchstart', start);
      window.removeEventListener('touchmove', move);
      window.removeEventListener('touchend', end);
      el.removeEventListener('mousedown', start);
      window.removeEventListener('mousemove', move);
      window.removeEventListener('mouseup', end);
    };
  // eslint-disable-next-line
  }, []);

  return (
    <div className="dpad" ref={baseRef} aria-label={label}>
      <div className="stick-base"></div>
      <div className="stick-knob" style={{ transform: `translate(calc(-50% + ${knob.x}px), calc(-50% + ${knob.y}px))` }}></div>
      <div className="stick-label">{label}</div>
    </div>
  );
}

/* Keyboard control hook */
function useKeyboard(onChange) {
  useEffect(() => {
    const keys = { up: false, down: false, left: false, right: false };
    const update = () => {
      const dx = (keys.right ? 1 : 0) - (keys.left ? 1 : 0);
      const dy = (keys.down ? 1 : 0) - (keys.up ? 1 : 0);
      const len = Math.hypot(dx, dy) || 1;
      onChange({ dx: dx / len, dy: dy / len });
    };
    const map = {
      'ArrowUp': 'up', 'KeyW': 'up',
      'ArrowDown': 'down', 'KeyS': 'down',
      'ArrowLeft': 'left', 'KeyA': 'left',
      'ArrowRight': 'right', 'KeyD': 'right',
    };
    const onDown = (e) => { if (map[e.code]) { keys[map[e.code]] = true; update(); e.preventDefault(); } };
    const onUp = (e) => { if (map[e.code]) { keys[map[e.code]] = false; update(); } };
    window.addEventListener('keydown', onDown);
    window.addEventListener('keyup', onUp);
    return () => { window.removeEventListener('keydown', onDown); window.removeEventListener('keyup', onUp); };
  // eslint-disable-next-line
  }, []);
}

/* Toast helper */
function useToast() {
  const [t, setT] = useState(null);
  const tid = useRef(null);
  const show = useCallback((msg, ms=1400) => {
    setT(msg);
    clearTimeout(tid.current);
    tid.current = setTimeout(() => setT(null), ms);
  }, []);
  const node = t ? <div className="toast">{t}</div> : null;
  return [show, node];
}

/* Universal action buttons — A (primary) + B (secondary). Shared across all games. */
function ActionButtons({ aLabel, aHint, bLabel, bHint, onA, onB, aDisabled, bDisabled, aActive, bActive }) {
  // Keyboard binding: J/Space = A, K = B
  useEffect(() => {
    const onDown = (e) => {
      if (e.repeat) return;
      if ((e.code === 'KeyJ' || e.code === 'Space') && !aDisabled) {
        e.preventDefault();
        onA && onA();
      } else if (e.code === 'KeyK' && !bDisabled && onB) {
        e.preventDefault();
        onB();
      }
    };
    window.addEventListener('keydown', onDown);
    return () => window.removeEventListener('keydown', onDown);
  }, [onA, onB, aDisabled, bDisabled]);

  return (
    <div className="action-pad">
      {bLabel && (
        <button
          className={`act-btn b${bActive ? ' active' : ''}`}
          onMouseDown={(e) => { e.preventDefault(); !bDisabled && onB && onB(); }}
          onTouchStart={(e) => { e.preventDefault(); !bDisabled && onB && onB(); }}
          disabled={bDisabled}>
          <span className="key-cap">B</span>
          <span className="lbl">{bLabel}</span>
          {bHint && <span className="hint">{bHint}</span>}
        </button>
      )}
      <button
        className={`act-btn a${aActive ? ' active' : ''}`}
        onMouseDown={(e) => { e.preventDefault(); !aDisabled && onA && onA(); }}
        onTouchStart={(e) => { e.preventDefault(); !aDisabled && onA && onA(); }}
        disabled={aDisabled}>
        <span className="key-cap">A</span>
        <span className="lbl">{aLabel || 'Action'}</span>
        {aHint && <span className="hint">{aHint}</span>}
      </button>
    </div>
  );
}

/* Universal robot physics — drives via joystick or keyboard.
   Returns ref to {x, y, vx, vy, angle} and a step function to call inside RAF loop. */
function useRobot({ x = 100, y = 200, speed = 2.6, smoothing = 0.18 }) {
  const ref = useRef({ x, y, vx: 0, vy: 0, angle: 0 });
  const inputRef = useRef({ dx: 0, dy: 0 });
  const setInput = useCallback((v) => { inputRef.current = v; }, []);
  const step = useCallback((bounds) => {
    const r = ref.current;
    const i = inputRef.current;
    r.vx += (i.dx * speed - r.vx) * smoothing;
    r.vy += (i.dy * speed - r.vy) * smoothing;
    r.x += r.vx;
    r.y += r.vy;
    if (bounds) {
      r.x = Math.max(bounds.minX ?? 0, Math.min(bounds.maxX ?? 9999, r.x));
      r.y = Math.max(bounds.minY ?? 0, Math.min(bounds.maxY ?? 9999, r.y));
    }
    if (Math.hypot(r.vx, r.vy) > 0.2) r.angle = Math.atan2(r.vy, r.vx);
  }, [speed, smoothing]);
  return { robotRef: ref, setInput, step, inputRef };
}

/* Standard robot SVG — draws the robot at its position with optional carry indicator. */
function RobotSprite({ robot, carrying, color = '#18171a', accent = 'oklch(0.82 0.19 128)' }) {
  const r = robot;
  return (
    <g transform={`translate(${r.x},${r.y}) rotate(${r.angle * 180 / Math.PI})`}>
      <rect x="-16" y="-12" width="32" height="24" rx="4" fill={color} />
      <rect x="-16" y="-15" width="32" height="4" fill={accent} opacity="0.7" />
      <circle cx="11" cy="-3" r="2.5" fill="#fff" />
      <circle cx="11" cy="3" r="2.5" fill="#fff" />
      <rect x="-14" y="-13" width="5" height="3" fill={accent} />
      <rect x="9" y="-13" width="5" height="3" fill={accent} />
      {carrying}
    </g>
  );
}

window.useTimer = useTimer;
window.HUD = HUD;
window.GameHeader = GameHeader;
window.NamePromptOverlay = NamePromptOverlay;
window.TutorialOverlay = TutorialOverlay;
window.ResultOverlay = ResultOverlay;
window.Joystick = Joystick;
window.useKeyboard = useKeyboard;
window.useToast = useToast;
window.ActionButtons = ActionButtons;
window.useRobot = useRobot;
window.RobotSprite = RobotSprite;
