// minesweeper.jsx — classic 9x9 / 10-mine Win95 minesweeper, hidden behind
// three unlock paths (Konami code, WINMINE on the boot screen, recycle-bin
// right-click → Properties). On win, the App's onWin handler calls the
// claimMinesweeperReward callable which awards 50 ★ and a one-shot coupon.

function MinesweeperContent({ user, onWin, onToast }) {
  const ROWS = 9, COLS = 9, MINES = 10;

  // Board cell shape: { mine: bool, revealed: bool, flagged: bool, n: number }
  const buildBoard = React.useCallback(() => {
    const cells = Array.from({ length: ROWS }, () =>
      Array.from({ length: COLS }, () => ({ mine: false, revealed: false, flagged: false, n: 0 }))
    );
    let placed = 0;
    while (placed < MINES) {
      const r = Math.floor(Math.random() * ROWS);
      const c = Math.floor(Math.random() * COLS);
      if (cells[r][c].mine) continue;
      cells[r][c].mine = true;
      placed++;
    }
    for (let r = 0; r < ROWS; r++) {
      for (let c = 0; c < COLS; c++) {
        if (cells[r][c].mine) continue;
        let n = 0;
        for (let dr = -1; dr <= 1; dr++) {
          for (let dc = -1; dc <= 1; dc++) {
            if (dr === 0 && dc === 0) continue;
            const nr = r + dr, nc = c + dc;
            if (nr < 0 || nr >= ROWS || nc < 0 || nc >= COLS) continue;
            if (cells[nr][nc].mine) n++;
          }
        }
        cells[r][c].n = n;
      }
    }
    return cells;
  }, []);

  const [board, setBoard] = React.useState(buildBoard);
  const [status, setStatus] = React.useState('playing'); // playing | won | lost
  const [flags, setFlags] = React.useState(0);
  const [seconds, setSeconds] = React.useState(0);
  const [started, setStarted] = React.useState(false);

  // Tick the timer once per second while playing.
  React.useEffect(() => {
    if (!started || status !== 'playing') return;
    const id = setInterval(() => setSeconds((s) => Math.min(999, s + 1)), 1000);
    return () => clearInterval(id);
  }, [started, status]);

  // Flood-fill empties when the user clicks a 0-cell.
  const reveal = (r, c, b) => {
    const stack = [[r, c]];
    while (stack.length) {
      const [r0, c0] = stack.pop();
      if (r0 < 0 || r0 >= ROWS || c0 < 0 || c0 >= COLS) continue;
      const cell = b[r0][c0];
      if (cell.revealed || cell.flagged) continue;
      cell.revealed = true;
      if (cell.n === 0 && !cell.mine) {
        for (let dr = -1; dr <= 1; dr++) {
          for (let dc = -1; dc <= 1; dc++) {
            if (dr === 0 && dc === 0) continue;
            stack.push([r0 + dr, c0 + dc]);
          }
        }
      }
    }
  };

  const checkWin = (b) => {
    for (let r = 0; r < ROWS; r++) {
      for (let c = 0; c < COLS; c++) {
        const cell = b[r][c];
        if (!cell.mine && !cell.revealed) return false;
      }
    }
    return true;
  };

  const click = (r, c) => {
    if (status !== 'playing') return;
    setStarted(true);
    if (window.apSound) window.apSound.click();
    setBoard((prev) => {
      const next = prev.map((row) => row.map((cell) => ({ ...cell })));
      const cell = next[r][c];
      if (cell.flagged) return next;
      if (cell.mine) {
        // Reveal all mines on loss.
        for (let rr = 0; rr < ROWS; rr++) {
          for (let cc = 0; cc < COLS; cc++) if (next[rr][cc].mine) next[rr][cc].revealed = true;
        }
        setStatus('lost');
        if (window.apSound) window.apSound.error();
        return next;
      }
      reveal(r, c, next);
      if (checkWin(next)) {
        setStatus('won');
        if (window.apSound) window.apSound.mail();
        if (typeof onWin === 'function') onWin();
      }
      return next;
    });
  };

  const flag = (r, c, e) => {
    if (e) { e.preventDefault(); e.stopPropagation(); }
    if (status !== 'playing') return;
    setBoard((prev) => {
      const next = prev.map((row) => row.map((cell) => ({ ...cell })));
      const cell = next[r][c];
      if (cell.revealed) return next;
      cell.flagged = !cell.flagged;
      setFlags((f) => f + (cell.flagged ? 1 : -1));
      if (window.apSound) window.apSound.click();
      return next;
    });
  };

  const reset = () => {
    setBoard(buildBoard());
    setStatus('playing');
    setFlags(0);
    setSeconds(0);
    setStarted(false);
  };

  // Long-press on touch devices acts as flag.
  const touchTimer = React.useRef(null);
  const onTouchStart = (r, c) => {
    if (touchTimer.current) clearTimeout(touchTimer.current);
    touchTimer.current = setTimeout(() => { flag(r, c); touchTimer.current = null; }, 450);
  };
  const onTouchEnd = (r, c) => {
    if (touchTimer.current) {
      clearTimeout(touchTimer.current);
      touchTimer.current = null;
      click(r, c);
    }
  };

  const numColor = (n) => ({ 1: '#0000ff', 2: '#008000', 3: '#ff0000', 4: '#000080', 5: '#800000', 6: '#008080', 7: '#000', 8: '#808080' }[n] || '#000');
  const face = status === 'won' ? '★' : status === 'lost' ? '☓' : '☺';
  const pad3 = (n) => String(Math.max(0, Math.min(999, n))).padStart(3, '0');

  return (
    <div style={{ padding: 6, fontSize: 12 }}>
      <div className="w95-inset" style={{ padding: 4, marginBottom: 6, background: '#c0c0c0', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ background: '#000', color: '#ff0000', fontFamily: 'monospace', fontSize: 16, padding: '2px 6px', minWidth: 44, textAlign: 'center' }}>
          {pad3(MINES - flags)}
        </div>
        <button onClick={reset} className="w95-btn" style={{ width: 28, height: 28, fontSize: 16, padding: 0 }}>
          {face}
        </button>
        <div style={{ background: '#000', color: '#ff0000', fontFamily: 'monospace', fontSize: 16, padding: '2px 6px', minWidth: 44, textAlign: 'center' }}>
          {pad3(seconds)}
        </div>
      </div>
      <div className="w95-inset" style={{ padding: 4, background: '#c0c0c0', display: 'inline-block' }}>
        <div style={{ display: 'grid', gridTemplateColumns: `repeat(${COLS}, 22px)`, gap: 0 }}>
          {board.map((row, r) => row.map((cell, c) => (
            <button key={`${r},${c}`}
              onClick={() => click(r, c)}
              onContextMenu={(e) => flag(r, c, e)}
              onTouchStart={() => onTouchStart(r, c)}
              onTouchEnd={() => onTouchEnd(r, c)}
              className={cell.revealed ? 'w95-inset' : 'w95-btn'}
              style={{
                width: 22, height: 22, padding: 0,
                fontSize: 12, fontWeight: 'bold', fontFamily: 'monospace',
                background: cell.revealed ? '#c0c0c0' : undefined,
                color: cell.mine && cell.revealed ? '#000' : numColor(cell.n),
                cursor: status === 'playing' ? 'pointer' : 'default',
              }}>
              {cell.flagged ? '⚑'
                : cell.revealed
                  ? (cell.mine ? '✸' : (cell.n > 0 ? cell.n : ''))
                  : ''}
            </button>
          )))}
        </div>
      </div>
      {status !== 'playing' && (
        <div style={{
          marginTop: 6, padding: 6, fontSize: 11, fontWeight: 'bold', textAlign: 'center',
          background: status === 'won' ? '#dfffdf' : '#ffe1e1',
          border: `1px solid ${status === 'won' ? '#080' : '#c00'}`,
          color: status === 'won' ? '#080' : '#900',
        }}>
          {status === 'won'
            ? '★ FIELD CLEARED ★ — claiming reward …'
            : '☓ DETONATED — press the face to retry'}
        </div>
      )}
      <div style={{ marginTop: 6, fontSize: 9, color: '#666', textAlign: 'center' }}>
        click to reveal · right-click (or long-press) to flag
      </div>
    </div>
  );
}

window.MinesweeperContent = MinesweeperContent;
