// saper.jsx
// Hidden easter-egg minefield — our OWN take, not Microsoft's assets.
// 8×8 grid, 10 mines, Dysbalans color system + terminal chrome.
// Opens on the 'dys:open-saper' window event (wired to the `/saper` console
// command). Esc closes. First click is always safe.

(function () {
  const { useState, useEffect, useCallback, useRef } = React;

  const SIZE = 8;
  const MINES = 10;

  function emptyBoard() {
    return Array.from({ length: SIZE }, () =>
      Array.from({ length: SIZE }, () => ({
        mine: false, adj: 0, revealed: false, flagged: false,
      }))
    );
  }

  // Place mines avoiding the first-clicked cell (+ its neighbors), compute adj.
  function buildBoard(safeR, safeC) {
    const b = emptyBoard();
    const banned = new Set();
    for (let dr = -1; dr <= 1; dr++)
      for (let dc = -1; dc <= 1; dc++)
        banned.add((safeR + dr) + ':' + (safeC + dc));

    let placed = 0;
    while (placed < MINES) {
      const r = Math.floor(Math.random() * SIZE);
      const c = Math.floor(Math.random() * SIZE);
      if (b[r][c].mine || banned.has(r + ':' + c)) continue;
      b[r][c].mine = true;
      placed++;
    }
    for (let r = 0; r < SIZE; r++) {
      for (let c = 0; c < SIZE; c++) {
        if (b[r][c].mine) continue;
        let n = 0;
        for (let dr = -1; dr <= 1; dr++)
          for (let dc = -1; dc <= 1; dc++) {
            const nr = r + dr, nc = c + dc;
            if (nr >= 0 && nr < SIZE && nc >= 0 && nc < SIZE && b[nr][nc].mine) n++;
          }
        b[r][c].adj = n;
      }
    }
    return b;
  }

  function cloneBoard(b) {
    return b.map((row) => row.map((cell) => ({ ...cell })));
  }

  function Saper() {
    const [open, setOpen] = useState(false);
    const [board, setBoard] = useState(emptyBoard);
    const [started, setStarted] = useState(false);
    const [status, setStatus] = useState('play'); // play | win | boom
    const [flags, setFlags] = useState(0);
    const [time, setTime] = useState(0);
    const timerRef = useRef(null);

    const reset = useCallback(() => {
      setBoard(emptyBoard());
      setStarted(false);
      setStatus('play');
      setFlags(0);
      setTime(0);
      clearInterval(timerRef.current);
    }, []);

    // open / close via console command + Esc
    useEffect(() => {
      function onOpen() { reset(); setOpen(true); }
      window.addEventListener('dys:open-saper', onOpen);
      return () => window.removeEventListener('dys:open-saper', onOpen);
    }, [reset]);

    // expose a global flag so the app's 1–4 / Esc handlers stand down while open
    useEffect(() => { window.__saperOpen = open; return () => { window.__saperOpen = false; }; }, [open]);

    useEffect(() => {
      if (!open) return;
      function onKey(e) {
        if (e.key === 'Escape') { e.preventDefault(); e.stopPropagation(); close(); }
      }
      window.addEventListener('keydown', onKey, true);
      return () => window.removeEventListener('keydown', onKey, true);
    }, [open]);

    // timer
    useEffect(() => {
      if (started && status === 'play') {
        timerRef.current = setInterval(() => setTime((t) => Math.min(999, t + 1)), 1000);
        return () => clearInterval(timerRef.current);
      }
      clearInterval(timerRef.current);
    }, [started, status]);

    function close() {
      clearInterval(timerRef.current);
      if (window.Audio && window.Audio.isEnabled()) window.Audio.woosh();
      setOpen(false);
    }

    function floodReveal(b, r, c) {
      const stack = [[r, c]];
      while (stack.length) {
        const [cr, cc] = stack.pop();
        if (cr < 0 || cr >= SIZE || cc < 0 || cc >= SIZE) continue;
        const cell = b[cr][cc];
        if (cell.revealed || cell.flagged) continue;
        cell.revealed = true;
        if (cell.adj === 0 && !cell.mine) {
          for (let dr = -1; dr <= 1; dr++)
            for (let dc = -1; dc <= 1; dc++)
              if (dr || dc) stack.push([cr + dr, cc + dc]);
        }
      }
    }

    function checkWin(b) {
      for (let r = 0; r < SIZE; r++)
        for (let c = 0; c < SIZE; c++)
          if (!b[r][c].mine && !b[r][c].revealed) return false;
      return true;
    }

    function revealCell(r, c) {
      if (status !== 'play') return;
      let b;
      if (!started) {
        b = buildBoard(r, c);
        setStarted(true);
      } else {
        b = cloneBoard(board);
      }
      const cell = b[r][c];
      if (cell.flagged || cell.revealed) return;

      if (cell.mine) {
        // boom — reveal all mines
        for (let rr = 0; rr < SIZE; rr++)
          for (let cc = 0; cc < SIZE; cc++)
            if (b[rr][cc].mine) b[rr][cc].revealed = true;
        cell.exploded = true;
        setBoard(b);
        setStatus('boom');
        if (window.Audio && window.Audio.isEnabled()) {
          window.Audio.blip(120); setTimeout(() => window.Audio.blip(70), 90);
        }
        return;
      }

      floodReveal(b, r, c);
      if (window.Audio && window.Audio.isEnabled()) window.Audio.blip(660);
      if (checkWin(b)) {
        setStatus('win');
        if (window.Audio && window.Audio.isEnabled()) window.Audio.woosh();
      }
      setBoard(b);
    }

    function toggleFlag(e, r, c) {
      e.preventDefault();
      if (status !== 'play' || !started) return;
      const b = cloneBoard(board);
      const cell = b[r][c];
      if (cell.revealed) return;
      cell.flagged = !cell.flagged;
      setFlags((f) => f + (cell.flagged ? 1 : -1));
      if (window.Audio && window.Audio.isEnabled()) window.Audio.tick();
      setBoard(b);
    }

    if (!open) return null;

    const minesLeft = Math.max(0, MINES - flags);    const face = status === 'boom' ? '× ×' : status === 'win' ? '^ ^' : 'o o';

    return (
      <div className="saper" role="dialog" aria-label="Saper">
        <div className="saper__scrim" onClick={close}></div>
        <div className={`saper__win saper__win--${status}`}>
          <div className="saper__titlebar">
            <span className="saper__title">SYS.MINEFIELD // saper.exe</span>
            <button className="saper__x" onClick={close}>[ESC]</button>
          </div>

          <div className="saper__hud">
            <span className="saper__counter">{String(minesLeft).padStart(2, '0')}<i>MINY</i></span>
            <button className="saper__face" onClick={reset} title="Reset">{face}</button>
            <span className="saper__counter">{String(time).padStart(3, '0')}<i>CZAS</i></span>
          </div>

          <div className="saper__grid" onContextMenu={(e) => e.preventDefault()}>
            {board.map((row, r) =>
              row.map((cell, c) => {
                const cls = ['saper__cell'];
                if (cell.revealed) cls.push('is-revealed');
                if (cell.exploded) cls.push('is-boom');
                if (cell.revealed && cell.adj) cls.push('n' + cell.adj);
                let glyph = '';
                if (cell.revealed) {
                  if (cell.mine) glyph = '✸';
                  else if (cell.adj) glyph = cell.adj;
                } else if (cell.flagged) {
                  glyph = '⚑';
                  cls.push('is-flag');
                }
                return (
                  <button
                    key={r + '-' + c}
                    className={cls.join(' ')}
                    onClick={() => revealCell(r, c)}
                    onContextMenu={(e) => toggleFlag(e, r, c)}
                  >{glyph}</button>
                );
              })
            )}
          </div>

          <div className="saper__foot">
            {status === 'play' && <span>LPM odkryj · PPM flaga · ESC wyjście</span>}
            {status === 'win' && <span className="saper__msg saper__msg--win">// POLE ROZBROJONE — {time}s</span>}
            {status === 'boom' && <span className="saper__msg saper__msg--boom">// DETONACJA — [reset] aby spróbować ponownie</span>}
          </div>
        </div>
      </div>
    );
  }

  Object.assign(window, { Saper });
})();
