// atelier-play.jsx — PlayScreen: continue playing against Stockfish from the
// lesson position.
//
// Flow on mount:
//   1. Load chess.js (via window.PlayGame.create), seed from window.LESSON.meta.fen
//   2. Apply the lesson's hero move so the user starts in the post-solution state
//      (their move has landed; it's the engine's turn)
//   3. Spin up window.PlayEngine.start(), set skill level, request engine reply
//
// Render:
//   - Left: AtelierBoard with positionOverride = game.positionMap(); click-to-move
//   - Right: move list, controls (restart, undo, level slider, think-time slider)

const { useState: useSP, useEffect: useEP, useMemo: useMP, useRef: useRP } = React;

const PLAY_SKILL_PRESETS = [
  { label: 'Casual',  level: 3,  desc: 'Loose. Good for warm-ups.' },
  { label: 'Club',    level: 8,  desc: 'Club-strength baseline.' },
  { label: 'Strong',  level: 12, desc: 'Punishes loose play.' },
  { label: 'Master',  level: 16, desc: 'Very few mistakes.' },
  { label: 'Max',     level: 20, desc: 'Engine at full strength.' },
];

function PlayScreen({ palette, tweaks, setRoute }) {
  const C = palette;
  const { isMobile, isTablet } = window.useBreakpoint();

  const lesson = window.LESSON;
  const meta = lesson && lesson.meta;
  const startFen = meta && meta.fen;
  const heroSq = lesson && lesson.hero;
  const heroTraj = lesson && lesson.trajectories && lesson.trajectories[heroSq];
  const heroTarget = heroTraj && heroTraj.length > 1 ? heroTraj[1] : null;
  const userColor = (meta && meta.sideToMove) === 'black' ? 'b' : 'w';
  const engineColor = userColor === 'w' ? 'b' : 'w';

  const [game, setGame] = useSP(null);
  const [engine, setEngine] = useSP(null);
  const [position, setPosition] = useSP(null);
  const [history, setHistory] = useSP([]);
  const [selected, setSelected] = useSP(null);
  const [legalDests, setLegalDests] = useSP([]);
  const [thinking, setThinking] = useSP(false);
  const [statusMsg, setStatusMsg] = useSP('Loading engine…');
  const [skillLevel, setSkillLevel] = useSP(8);
  const [movetime, setMovetime] = useSP(800);
  const [gameOver, setGameOver] = useSP(null);

  const engineRef = useRP(null);
  const gameRef = useRP(null);
  const thinkSeqRef = useRP(0);

  // ── Initial mount: build the game + engine ─────────────────────────────────
  useEP(() => {
    if (!startFen) {
      setStatusMsg('No lesson loaded. Pick one from Home.');
      return undefined;
    }
    let cancelled = false;
    let localEngine = null;

    (async () => {
      const g = await window.PlayGame.create(startFen);
      if (cancelled) return;
      if (heroSq && heroTarget) {
        const uci = g.uciFor(heroSq, heroTarget) || (heroSq + heroTarget);
        g.moveFromUci(uci);
      }
      gameRef.current = g;
      setGame(g);
      setPosition(g.positionMap());
      setHistory(g.history());

      try {
        localEngine = window.PlayEngine.start();
        await localEngine.ready();
      } catch (err) {
        if (!cancelled) setStatusMsg('Engine failed to load. ' + (err.message || err));
        return;
      }
      if (cancelled) { localEngine.terminate(); return; }
      engineRef.current = localEngine;
      setEngine(localEngine);
      localEngine.newGame();
      localEngine.setSkillLevel(skillLevel);

      setStatusMsg('Your move.');
      if (g.turn() === engineColor && !g.isGameOver()) {
        askEngine(g, localEngine);
      }
    })();

    return () => {
      cancelled = true;
      if (localEngine) localEngine.terminate();
    };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [startFen]);

  function askEngine(g, eng) {
    if (!g || !eng) return;
    if (g.isGameOver()) return;
    const mySeq = ++thinkSeqRef.current;
    setThinking(true);
    setStatusMsg('Stockfish is thinking…');
    const moves = g.history().map((m) => m.from + m.to + (m.promotion || ''));
    eng.setPosition(g.initialFen, moves);
    eng.requestMove({ movetime })
      .then(({ bestmove }) => {
        if (mySeq !== thinkSeqRef.current) return;
        if (!bestmove || bestmove === '(none)') {
          setThinking(false);
          finishGame(g);
          return;
        }
        g.moveFromUci(bestmove);
        setPosition(g.positionMap());
        setHistory(g.history());
        setThinking(false);
        if (g.isGameOver()) finishGame(g);
        else setStatusMsg('Your move.');
      })
      .catch((err) => {
        if (mySeq !== thinkSeqRef.current) return;
        if (err && err.message === 'superseded') return;
        setThinking(false);
        setStatusMsg('Engine error: ' + (err && err.message ? err.message : err));
      });
  }

  function finishGame(g) {
    const s = g.status();
    setGameOver(s);
    if (s === 'checkmate') {
      const loser = g.turn();
      setStatusMsg(loser === userColor ? 'Checkmate — Stockfish won.' : 'Checkmate — you won!');
    } else if (s === 'stalemate') {
      setStatusMsg('Stalemate. The game is a draw.');
    } else {
      setStatusMsg('Draw.');
    }
  }

  function onPieceSelect(sq) {
    if (!game || thinking || gameOver) return;
    if (game.turn() !== userColor) return;
    if (sq == null) { setSelected(null); setLegalDests([]); return; }
    if (selected && legalDests.includes(sq)) {
      makeUserMove(selected, sq);
      return;
    }
    const code = game.positionMap()[sq];
    if (!code) { setSelected(null); setLegalDests([]); return; }
    if (code[0] !== userColor) return;
    const moves = game.legalMovesFrom(sq);
    setSelected(sq);
    setLegalDests(moves.map((m) => m.to));
  }

  function onSquareClick(sq) {
    if (!game || thinking || gameOver) return;
    if (game.turn() !== userColor) return;
    if (!selected) return;
    if (!legalDests.includes(sq)) {
      setSelected(null);
      setLegalDests([]);
      return;
    }
    makeUserMove(selected, sq);
  }

  function makeUserMove(from, to) {
    const g = gameRef.current;
    const eng = engineRef.current;
    if (!g) return;
    const uci = g.uciFor(from, to);
    if (!uci) {
      setSelected(null);
      setLegalDests([]);
      return;
    }
    g.moveFromUci(uci);
    setPosition(g.positionMap());
    setHistory(g.history());
    setSelected(null);
    setLegalDests([]);
    if (g.isGameOver()) { finishGame(g); return; }
    if (eng) askEngine(g, eng);
  }

  function restart() {
    const g = gameRef.current;
    const eng = engineRef.current;
    if (!g) return;
    thinkSeqRef.current++;
    g.reset();
    if (heroSq && heroTarget) {
      const uci = g.uciFor(heroSq, heroTarget) || (heroSq + heroTarget);
      g.moveFromUci(uci);
    }
    setPosition(g.positionMap());
    setHistory(g.history());
    setSelected(null);
    setLegalDests([]);
    setGameOver(null);
    setThinking(false);
    if (eng) eng.newGame();
    if (g.turn() === engineColor && !g.isGameOver()) askEngine(g, eng);
    else setStatusMsg('Your move.');
  }

  function undo() {
    const g = gameRef.current;
    const eng = engineRef.current;
    if (!g) return;
    thinkSeqRef.current++;
    setThinking(false);
    let popped = 0;
    while (g.history().length > 1 && popped < 2) {
      g.undo();
      popped++;
      if (g.turn() === userColor) break;
    }
    setPosition(g.positionMap());
    setHistory(g.history());
    setSelected(null);
    setLegalDests([]);
    setGameOver(null);
    setStatusMsg('Your move.');
    if (eng) eng.newGame();
  }

  function applyLevel(n) {
    setSkillLevel(n);
    if (engineRef.current) engineRef.current.setSkillLevel(n);
  }

  const boardSize = isMobile ? Math.min(320, window.innerWidth - 48) : 560;
  const markedSquares = useMP(() => {
    if (!selected) return null;
    return legalDests.map((sq) => ({ sq, label: '·' }));
  }, [selected, legalDests]);

  const title = (lesson && window.creativeTitle) ? window.creativeTitle(lesson.id) : 'Play it out';
  const kicker = (meta && meta.theme && window.creativeSubtitle)
    ? 'Play vs Stockfish · ' + window.creativeSubtitle(meta.theme)
    : 'Play vs Stockfish';

  return (
    <div style={{ flex: 1, height: '100%', overflow: 'hidden', display: 'flex', flexDirection: 'column', background: C.bone }}>
      <window.Topbar palette={C} kicker={kicker} title={title}
        rightSlot={
          <button
            onClick={() => setRoute && setRoute('puzzle')}
            style={{
              appearance: 'none', cursor: 'pointer',
              padding: '7px 14px', borderRadius: 99,
              border: `0.6px solid ${C.umberHair}`,
              background: 'transparent', color: C.umberSoft,
              fontFamily: window.ATELIER_TYPE.ui, fontSize: 10,
              letterSpacing: 2, textTransform: 'uppercase',
            }}
          >Back to study</button>
        }
      />
      <div style={{
        flex: 1, overflow: isTablet ? 'auto' : 'hidden',
        display: 'grid',
        gridTemplateColumns: isTablet ? '1fr' : 'minmax(0, 1fr) 360px',
      }}>
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          flexDirection: 'column', gap: 14, padding: 24,
          background: `radial-gradient(120% 80% at 50% -10%, ${window.withAlpha(C.brassLight, 0.3)}, transparent 60%)`,
          overflow: 'auto',
        }}>
          {position ? (
            <div style={{
              background: C.boneDeep, padding: 12, borderRadius: 8,
              boxShadow: '0 30px 50px -28px rgba(42,34,27,0.45)',
            }}>
              <window.AtelierBoard
                palette={C}
                layers={{ heatmap: false, hero: false, trajectory: false, tension: false }}
                heatmapStyle={tweaks.heatmapStyle}
                heatmapIntensity={tweaks.heatmapIntensity}
                trajectoryStyle={tweaks.trajectoryStyle}
                selected={selected}
                onSelect={onPieceSelect}
                onSquareClick={onSquareClick}
                markedSquares={markedSquares}
                size={boardSize}
                noTrajectoryOnSelect={true}
                positionOverride={position}
              />
            </div>
          ) : (
            <div style={{
              padding: 60, fontFamily: window.ATELIER_TYPE.display, fontStyle: 'italic',
              fontSize: 16, color: C.umberSoft, textAlign: 'center',
            }}>{statusMsg}</div>
          )}
          <div style={{
            fontFamily: window.ATELIER_TYPE.display, fontStyle: 'italic',
            fontSize: 14, color: C.umberSoft, minHeight: 18,
          }}>{statusMsg}</div>
        </div>

        <aside style={{
          background: C.cream,
          borderLeft: isTablet ? 'none' : `0.6px solid ${C.umberHair}`,
          borderTop: isTablet ? `0.6px solid ${C.umberHair}` : 'none',
          padding: isMobile ? '20px 16px' : '24px 24px',
          display: 'flex', flexDirection: 'column', gap: 18,
          overflow: 'auto',
        }}>
          <PlayMoveList palette={C} history={history} />
          <PlayGameOverBanner palette={C} status={gameOver} onRestart={restart} onBackToLesson={() => setRoute && setRoute('lesson')} />
          <PlayControls
            palette={C}
            skillLevel={skillLevel}
            onSkillLevel={applyLevel}
            movetime={movetime}
            onMovetime={setMovetime}
            onRestart={restart}
            onUndo={undo}
            canUndo={history.length > 1}
            thinking={thinking}
          />
        </aside>
      </div>
    </div>
  );
}

function PlayMoveList({ palette, history }) {
  const C = palette;
  const pairs = useMP(() => {
    const result = [];
    for (let i = 0; i < history.length; i += 2) {
      result.push([history[i], history[i + 1] || null]);
    }
    return result;
  }, [history]);

  return (
    <div>
      <div style={{
        fontFamily: window.ATELIER_TYPE.ui, fontSize: 9, letterSpacing: 3,
        textTransform: 'uppercase', color: C.umberFaint, marginBottom: 8,
      }}>Moves</div>
      <div style={{
        background: C.bone, border: `0.6px solid ${C.umberHair}`, borderRadius: 10,
        padding: pairs.length ? '8px 10px' : '14px 12px',
        fontFamily: window.ATELIER_TYPE.display, fontSize: 14, color: C.umber,
        minHeight: 60, maxHeight: 220, overflow: 'auto',
      }}>
        {pairs.length === 0 ? (
          <span style={{ fontStyle: 'italic', color: C.umberFaint }}>No moves yet.</span>
        ) : pairs.map(([w, b], i) => (
          <div key={i} style={{ display: 'flex', gap: 10, padding: '2px 0' }}>
            <span style={{
              fontFamily: window.ATELIER_TYPE.ui, fontSize: 11, color: C.umberFaint, minWidth: 24,
            }}>{i + 1}.</span>
            <span style={{ minWidth: 56 }}>{w ? w.san : ''}</span>
            <span style={{ minWidth: 56 }}>{b ? b.san : ''}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

function PlayGameOverBanner({ palette, status, onRestart, onBackToLesson }) {
  const C = palette;
  if (!status) return null;
  const label = status === 'checkmate' ? 'Checkmate'
             : status === 'stalemate' ? 'Stalemate'
             : 'Draw';
  return (
    <div style={{
      padding: '14px 16px', borderRadius: 12,
      background: window.withAlpha(C.brass, 0.16),
      border: `0.6px solid ${C.brass}`,
    }}>
      <div style={{
        fontFamily: window.ATELIER_TYPE.ui, fontSize: 9, letterSpacing: 3,
        textTransform: 'uppercase', color: C.brassDeep, marginBottom: 6,
      }}>Game over</div>
      <div style={{
        fontFamily: window.ATELIER_TYPE.display, fontStyle: 'italic',
        fontSize: 18, color: C.umber, marginBottom: 10,
      }}>{label}</div>
      <div style={{ display: 'flex', gap: 8 }}>
        <button style={window.ghostBtn(C)} onClick={onBackToLesson}>Back to study</button>
        <button style={window.primaryBtn(C)} onClick={onRestart}>Play again</button>
      </div>
    </div>
  );
}

function PlayControls({ palette, skillLevel, onSkillLevel, movetime, onMovetime, onRestart, onUndo, canUndo, thinking }) {
  const C = palette;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div>
        <div style={{
          fontFamily: window.ATELIER_TYPE.ui, fontSize: 9, letterSpacing: 3,
          textTransform: 'uppercase', color: C.umberFaint, marginBottom: 8,
        }}>Stockfish level</div>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 8 }}>
          {PLAY_SKILL_PRESETS.map((p) => {
            const active = skillLevel === p.level;
            return (
              <button key={p.label} onClick={() => onSkillLevel(p.level)}
                title={p.desc}
                style={{
                  appearance: 'none', cursor: 'pointer',
                  padding: '6px 11px', borderRadius: 99,
                  border: `0.6px solid ${active ? C.umber : C.umberHair}`,
                  background: active ? C.umber : C.cream,
                  color: active ? C.cream : C.umberSoft,
                  fontFamily: window.ATELIER_TYPE.ui, fontSize: 10,
                  letterSpacing: 1.5, textTransform: 'uppercase',
                }}>{p.label}</button>
            );
          })}
        </div>
        <input
          type="range" min="0" max="20" step="1"
          value={skillLevel}
          onChange={(e) => onSkillLevel(parseInt(e.target.value, 10))}
          style={{ width: '100%' }}
        />
        <div style={{
          fontFamily: window.ATELIER_TYPE.ui, fontSize: 10, letterSpacing: 1,
          color: C.umberFaint, marginTop: 2,
        }}>Skill {skillLevel} / 20</div>
      </div>

      <div>
        <div style={{
          fontFamily: window.ATELIER_TYPE.ui, fontSize: 9, letterSpacing: 3,
          textTransform: 'uppercase', color: C.umberFaint, marginBottom: 8,
        }}>Engine think time</div>
        <input
          type="range" min="100" max="3000" step="100"
          value={movetime}
          onChange={(e) => onMovetime(parseInt(e.target.value, 10))}
          style={{ width: '100%' }}
        />
        <div style={{
          fontFamily: window.ATELIER_TYPE.ui, fontSize: 10, letterSpacing: 1,
          color: C.umberFaint, marginTop: 2,
        }}>{movetime} ms</div>
      </div>

      <div style={{ display: 'flex', gap: 8 }}>
        <button
          style={{ ...window.ghostBtn(C), flex: 1, opacity: canUndo && !thinking ? 1 : 0.4, cursor: canUndo && !thinking ? 'pointer' : 'not-allowed' }}
          disabled={!canUndo || thinking}
          onClick={onUndo}>Undo</button>
        <button
          style={{ ...window.ghostBtn(C), flex: 1 }}
          onClick={onRestart}>Restart</button>
      </div>
    </div>
  );
}

Object.assign(window, { PlayScreen });
