// gameplay.jsx — the playable math games.
//
// One runner per id in MATH_GAMES. They all share:
//   - a small RunnerShell that displays progress, problem, and feedback
//   - a Numpad for arithmetic answers (Addisjon, Subtraksjon, Divisjon)
//   - a ChoicePad for multiple choice answers (Multiplikasjon, Klokka, Former, Telling)
//   - a NumberLine drag input for Tallinje
//
// Each runner reads its parameters via mapDifficultyToParams(gameId, difficulty)
// so the only file that knows how a game scales with skill is adaptive.jsx.
// Every round dispatches { correct, msToAnswer, difficulty } so the shared
// pipeline can adjust difficulty and weight the lottery on the next visit.

const RUNNER_ROUNDS = 5;

function rand(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
function pick(arr) { return arr[Math.floor(Math.random() * arr.length)]; }
function shuffle(arr) {
  const a = [...arr];
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

// Shared shell: progress dots at top, problem area, feedback flash, finish state.
// Children render the question and the input UI; the shell owns the round loop.
function RunnerShell({ gameId, profile, onFinish, generateRound, renderProblem }) {
  const slot = profile.perGame?.[gameId];
  const difficulty = slot?.difficulty ?? seedDifficulty(profile.age, gameId);
  const params = mapDifficultyToParams(gameId, difficulty);
  const totalRounds = params.rounds ?? RUNNER_ROUNDS;

  const [roundIndex, setRoundIndex] = React.useState(0);
  const [round, setRound] = React.useState(() => generateRound(params));
  const [results, setResults] = React.useState([]);
  const [feedback, setFeedback] = React.useState(null); // 'correct' | 'wrong' | null
  const startedAtRef = React.useRef(performance.now());

  React.useEffect(() => { startedAtRef.current = performance.now(); }, [roundIndex]);

  const submitAnswer = (answer) => {
    if (feedback) return; // ignore taps during feedback animation
    const correct = round.check(answer);
    const ms = performance.now() - startedAtRef.current;
    const result = { correct, msToAnswer: ms, difficulty };
    const nextResults = [...results, result];
    setFeedback(correct ? 'correct' : 'wrong');
    setResults(nextResults);
    setTimeout(() => {
      setFeedback(null);
      if (roundIndex + 1 >= totalRounds) {
        const correctCount = nextResults.filter(r => r.correct).length;
        const passed = correctCount >= Math.ceil(totalRounds * 0.6); // 3/5 to pass
        onFinish({ passed, rounds: nextResults });
      } else {
        setRound(generateRound(params));
        setRoundIndex(roundIndex + 1);
      }
    }, correct ? 600 : 900);
  };

  return (
    <div className={`runner ${feedback ? 'fb-' + feedback : ''}`}>
      <div className="runner-progress">
        {Array.from({ length: totalRounds }).map((_, i) => (
          <span key={i} className={
            i < results.length
              ? (results[i].correct ? 'dot dot-ok' : 'dot dot-no')
              : (i === roundIndex ? 'dot dot-now' : 'dot')
          } />
        ))}
      </div>
      <div className="runner-stage">
        {renderProblem(round, submitAnswer)}
      </div>
      {feedback === 'correct' && <div className="runner-flash ok">Riktig! 🎉</div>}
      {feedback === 'wrong' && <div className="runner-flash no">Prøv neste! 💪</div>}
    </div>
  );
}

// ── Numpad ──────────────────────────────────────────────────────────────────

function Numpad({ value, onInput, onClear, onSubmit, maxLength = 4 }) {
  const press = (d) => {
    if (String(value).length >= maxLength) return;
    onInput(d);
  };
  return (
    <div className="numpad">
      <div className="numpad-display">{value === '' ? '?' : value}</div>
      <div className="numpad-grid">
        {[1,2,3,4,5,6,7,8,9].map(n => (
          <button key={n} className="numpad-key" onClick={() => press(String(n))}>{n}</button>
        ))}
        <button className="numpad-key numpad-clear" onClick={onClear}>⌫</button>
        <button className="numpad-key" onClick={() => press('0')}>0</button>
        <button className="numpad-key numpad-ok" onClick={onSubmit} disabled={value === ''}>OK</button>
      </div>
    </div>
  );
}

// ── ChoicePad: 4 large bubble buttons ───────────────────────────────────────

function ChoicePad({ choices, onPick, render }) {
  return (
    <div className="choicepad">
      {choices.map((c, i) => (
        <button key={i} className={`choice choice-${i}`} onClick={() => onPick(c)}>
          {render ? render(c) : c}
        </button>
      ))}
    </div>
  );
}

// ── Helpers used by several runners ─────────────────────────────────────────

function uniqueChoices(correct, makeDecoy, count = 4) {
  const set = new Set([correct]);
  let safety = 0;
  while (set.size < count && safety++ < 200) set.add(makeDecoy());
  return shuffle([...set]);
}

// ── Runners ─────────────────────────────────────────────────────────────────

function ArithmeticRunner({ gameId, profile, onFinish, makeRound, label }) {
  return (
    <RunnerShell
      gameId={gameId}
      profile={profile}
      onFinish={onFinish}
      generateRound={makeRound}
      renderProblem={(round, submit) => <NumpadProblem round={round} submit={submit} label={label} />}
    />
  );
}

function NumpadProblem({ round, submit, label }) {
  const [value, setValue] = React.useState('');
  React.useEffect(() => { setValue(''); }, [round]);
  return (
    <>
      {label && <div className="runner-label">{label}</div>}
      <div className="runner-question">{round.text}</div>
      <Numpad
        value={value}
        onInput={(d) => setValue(v => v + d)}
        onClear={() => setValue('')}
        onSubmit={() => { submit(Number(value)); setValue(''); }}
      />
    </>
  );
}

function AddisjonRunner({ profile, onFinish }) {
  const make = (p) => {
    const a = rand(p.min, p.max);
    const b = rand(p.min, p.max);
    return { text: `${a} + ${b} = ?`, check: (ans) => ans === a + b };
  };
  return <ArithmeticRunner gameId="addisjon" profile={profile} onFinish={onFinish} makeRound={make} />;
}

function SubtraksjonRunner({ profile, onFinish }) {
  const make = (p) => {
    let a = rand(p.min, p.max);
    let b = rand(p.min, p.max);
    if (!p.allowNegative && b > a) [a, b] = [b, a];
    return { text: `${a} − ${b} = ?`, check: (ans) => ans === a - b };
  };
  return <ArithmeticRunner gameId="subtraksjon" profile={profile} onFinish={onFinish} makeRound={make} />;
}

function MultiplikasjonRunner({ profile, onFinish }) {
  const make = (p) => {
    const a = rand(p.minFactor, p.maxFactor);
    const b = rand(p.minFactor, p.maxFactor);
    const correct = a * b;
    const choices = uniqueChoices(correct, () => {
      const da = a + rand(-2, 2);
      const db = b + rand(-2, 2);
      return Math.max(0, da) * Math.max(0, db);
    });
    return {
      text: `${a} × ${b}`,
      choices,
      check: (ans) => ans === correct,
    };
  };
  const render = (round, submit) => (
    <>
      <div className="runner-question">{round.text}</div>
      <ChoicePad choices={round.choices} onPick={(c) => submit(c)} />
    </>
  );
  return (
    <RunnerShell
      gameId="multiplikasjon"
      profile={profile}
      onFinish={onFinish}
      generateRound={make}
      renderProblem={render}
    />
  );
}

function DivisjonRunner({ profile, onFinish }) {
  const make = (p) => {
    // Construct from quotient × divisor so the result is always a clean integer.
    const q = rand(1, p.maxQ);
    const d = rand(1, p.maxDiv);
    const a = q * d;
    return { text: `${a} ÷ ${d} = ?`, check: (ans) => ans === q };
  };
  return <ArithmeticRunner gameId="divisjon" profile={profile} onFinish={onFinish} makeRound={make} />;
}

// ── Klokka ──────────────────────────────────────────────────────────────────

function ClockFace({ hour, minute, size = 180 }) {
  const cx = size / 2, cy = size / 2;
  const r = size / 2 - 6;
  const minuteAngle = (minute / 60) * 360 - 90;
  const hourAngle = (((hour % 12) + minute / 60) / 12) * 360 - 90;
  const h = (a, len) => ({
    x2: cx + Math.cos(a * Math.PI / 180) * len,
    y2: cy + Math.sin(a * Math.PI / 180) * len,
  });
  const hh = h(hourAngle, r * 0.55);
  const mh = h(minuteAngle, r * 0.78);
  const ticks = Array.from({ length: 12 }).map((_, i) => {
    const a = (i / 12) * 360 - 90;
    const x1 = cx + Math.cos(a * Math.PI / 180) * (r - 8);
    const y1 = cy + Math.sin(a * Math.PI / 180) * (r - 8);
    const x2 = cx + Math.cos(a * Math.PI / 180) * r;
    const y2 = cy + Math.sin(a * Math.PI / 180) * r;
    return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke="#1F2D4A" strokeWidth="2" strokeLinecap="round" />;
  });
  return (
    <svg viewBox={`0 0 ${size} ${size}`} width={size} height={size} className="clock-face">
      <circle cx={cx} cy={cy} r={r} fill="#fff" stroke="#1F2D4A" strokeWidth="3" />
      {ticks}
      <line x1={cx} y1={cy} x2={hh.x2} y2={hh.y2} stroke="#1F2D4A" strokeWidth="5" strokeLinecap="round" />
      <line x1={cx} y1={cy} x2={mh.x2} y2={mh.y2} stroke="#FF7AB8" strokeWidth="3" strokeLinecap="round" />
      <circle cx={cx} cy={cy} r="5" fill="#1F2D4A" />
    </svg>
  );
}

function fmtTime(h, m) {
  return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
}

function KlokkaRunner({ profile, onFinish }) {
  const make = (p) => {
    const granularity = p.granularity || 60;
    const h = rand(1, 12);
    const m = (rand(0, Math.floor(60 / granularity) - 1) * granularity) % 60;
    const correct = fmtTime(h, m);
    const choices = uniqueChoices(correct, () => {
      const hh = rand(1, 12);
      const mm = (rand(0, Math.floor(60 / granularity) - 1) * granularity) % 60;
      return fmtTime(hh, mm);
    });
    return { hour: h, minute: m, choices, check: (ans) => ans === correct };
  };
  const render = (round, submit) => (
    <>
      <div className="runner-label">Hva er klokka?</div>
      <ClockFace hour={round.hour} minute={round.minute} />
      <ChoicePad choices={round.choices} onPick={(c) => submit(c)} />
    </>
  );
  return (
    <RunnerShell gameId="klokka" profile={profile} onFinish={onFinish}
      generateRound={make} renderProblem={render} />
  );
}

// ── Former / Geometri ───────────────────────────────────────────────────────

const SHAPES = [
  { name: 'sirkel',     draw: <circle cx="50" cy="50" r="38" /> },
  { name: 'kvadrat',    draw: <rect x="14" y="14" width="72" height="72" rx="2" /> },
  { name: 'trekant',    draw: <polygon points="50,10 90,84 10,84" /> },
  { name: 'rektangel',  draw: <rect x="8" y="28" width="84" height="44" rx="2" /> },
  { name: 'femkant',    draw: <polygon points="50,10 90,40 75,84 25,84 10,40" /> },
  { name: 'sekskant',   draw: <polygon points="50,10 86,30 86,70 50,90 14,70 14,30" /> },
  { name: 'oval',       draw: <ellipse cx="50" cy="50" rx="40" ry="26" /> },
  { name: 'romber',     draw: <polygon points="50,10 90,50 50,90 10,50" /> },
  { name: 'stjerne',    draw: <polygon points="50,8 60,40 92,40 66,58 76,90 50,72 24,90 34,58 8,40 40,40" /> },
  { name: 'hjerte',     draw: <path d="M50 86 C 12 60, 12 22, 38 22 C 46 22, 50 30, 50 36 C 50 30, 54 22, 62 22 C 88 22, 88 60, 50 86 Z" /> },
];

function FormerRunner({ profile, onFinish }) {
  const make = (p) => {
    const set = SHAPES.slice(0, p.shapeCount || 4);
    const correct = pick(set);
    const others = set.filter(s => s.name !== correct.name);
    const decoys = shuffle(others).slice(0, 3).map(s => s.name);
    const choices = shuffle([correct.name, ...decoys]);
    return { shape: correct, choices, check: (ans) => ans === correct.name };
  };
  const render = (round, submit) => (
    <>
      <div className="runner-label">Hvilken form er dette?</div>
      <svg viewBox="0 0 100 100" width="160" height="160" className="shape-display">
        {React.cloneElement(round.shape.draw, { fill: '#FF7AB8', stroke: '#9B72E8', strokeWidth: 2 })}
      </svg>
      <ChoicePad choices={round.choices} onPick={(c) => submit(c)} />
    </>
  );
  return (
    <RunnerShell gameId="former" profile={profile} onFinish={onFinish}
      generateRound={make} renderProblem={render} />
  );
}

// ── Telling ─────────────────────────────────────────────────────────────────

const COUNT_EMOJIS = ['☁️', '⭐', '🦄', '🌸', '🎈', '🐱', '🍭', '🌈'];

function TellingRunner({ profile, onFinish }) {
  const make = (p) => {
    const target = pick(COUNT_EMOJIS);
    const count = rand(2, p.maxCount || 10);
    const items = Array.from({ length: count }, () => target);
    if (p.addNoise) {
      const decoy = pick(COUNT_EMOJIS.filter(e => e !== target));
      const noise = rand(2, Math.max(2, Math.floor(count * 0.4)));
      for (let i = 0; i < noise; i++) items.push(decoy);
    }
    return {
      target,
      items: shuffle(items),
      count,
      choices: uniqueChoices(count, () => Math.max(1, count + rand(-3, 3))),
      check: (ans) => ans === count,
    };
  };
  const render = (round, submit) => (
    <>
      <div className="runner-label">Hvor mange {round.target} ser du?</div>
      <div className="count-board">
        {round.items.map((e, i) => <span key={i} className="count-item">{e}</span>)}
      </div>
      <ChoicePad choices={round.choices} onPick={(c) => submit(c)} />
    </>
  );
  return (
    <RunnerShell gameId="telling" profile={profile} onFinish={onFinish}
      generateRound={make} renderProblem={render} />
  );
}

// ── Tallinje ────────────────────────────────────────────────────────────────

function TallinjeRunner({ profile, onFinish }) {
  const make = (p) => {
    const max = p.maxValue || 10;
    const target = rand(1, max - 1);
    return { max, target, ticks: p.ticks || 11, check: (ans) => Math.abs(ans - target) <= Math.max(1, Math.round(max * 0.04)) };
  };
  const render = (round, submit) => <NumberLineProblem round={round} submit={submit} />;
  return (
    <RunnerShell gameId="tallinje" profile={profile} onFinish={onFinish}
      generateRound={make} renderProblem={render} />
  );
}

function NumberLineProblem({ round, submit }) {
  const [pos, setPos] = React.useState(round.max / 2);
  const lineRef = React.useRef(null);
  React.useEffect(() => { setPos(round.max / 2); }, [round]);
  const onPointerMove = (clientX) => {
    const r = lineRef.current.getBoundingClientRect();
    const ratio = Math.max(0, Math.min(1, (clientX - r.left) / r.width));
    setPos(Math.round(ratio * round.max));
  };
  const onPointerDown = (e) => {
    onPointerMove(e.clientX);
    const move = (ev) => onPointerMove(ev.clientX);
    const up = () => {
      window.removeEventListener('pointermove', move);
      window.removeEventListener('pointerup', up);
    };
    window.addEventListener('pointermove', move);
    window.addEventListener('pointerup', up);
  };
  const ticks = Array.from({ length: round.ticks }).map((_, i) => {
    const v = Math.round((i / (round.ticks - 1)) * round.max);
    return { v, left: `${(i / (round.ticks - 1)) * 100}%` };
  });
  return (
    <>
      <div className="runner-label">Dra prikken til tallet</div>
      <div className="runner-question">{round.target}</div>
      <div className="numline" ref={lineRef} onPointerDown={onPointerDown}>
        <div className="numline-track" />
        {ticks.map((t, i) => (
          <div key={i} className="numline-tick" style={{ left: t.left }}>
            <span>{t.v}</span>
          </div>
        ))}
        <div className="numline-marker"
             style={{ left: `${(pos / round.max) * 100}%` }}>
          <span>{pos}</span>
        </div>
      </div>
      <div className="modal-actions">
        <button className="btn-primary" onClick={() => submit(pos)}>Plasser</button>
      </div>
    </>
  );
}

// ── Dispatch ────────────────────────────────────────────────────────────────

const RUNNERS = {
  addisjon: AddisjonRunner,
  subtraksjon: SubtraksjonRunner,
  multiplikasjon: MultiplikasjonRunner,
  divisjon: DivisjonRunner,
  klokka: KlokkaRunner,
  former: FormerRunner,
  telling: TellingRunner,
  tallinje: TallinjeRunner,
};

function GameRunner({ gameId, profile, onFinish }) {
  const Runner = RUNNERS[gameId];
  if (!Runner) {
    return (
      <div className="modal-body">
        <p>Spillet kommer snart!</p>
        <div className="modal-actions">
          <button className="btn-primary" onClick={() => onFinish({ passed: false, rounds: [] })}>
            Tilbake
          </button>
        </div>
      </div>
    );
  }
  return <Runner profile={profile} onFinish={onFinish} />;
}

Object.assign(window, {
  GameRunner,
  RunnerShell,
  Numpad,
  ChoicePad,
  AddisjonRunner,
  SubtraksjonRunner,
  MultiplikasjonRunner,
  DivisjonRunner,
  KlokkaRunner,
  FormerRunner,
  TellingRunner,
  TallinjeRunner,
});
