// Bubble Maze — navigate through grid mazes, arrow keys + d-pad + swipe
function BubbleMazeGame() {

  // Mazes: '#' wall, ' ' path, 'S' start, 'E' exit, '*' star collectible
  const LEVELS = [
    {
      label: 'Level 1', rows: 7, cols: 9,
      grid: [
        '#########',
        '#S  #   #',
        '# # # # #',
        '# #   # #',
        '# ##### #',
        '#     * E',
        '#########',
      ],
    },
    {
      label: 'Level 2', rows: 9, cols: 11,
      grid: [
        '###########',
        '#S#   #   #',
        '# # # # # #',
        '#   #   # #',
        '### ##### #',
        '#   #   # #',
        '# ### # # #',
        '#   * #  E#',
        '###########',
      ],
    },
    {
      label: 'Level 3', rows: 11, cols: 13,
      grid: [
        '#############',
        '#S  #   #   #',
        '# # # # # # #',
        '# #   # # # #',
        '# ##### # # #',
        '#       # # #',
        '# ####### # #',
        '# #   #   # #',
        '# # # # ### #',
        '#   # *     E',
        '#############',
      ],
    },
    {
      label: 'Level 4', rows: 11, cols: 15,
      grid: [
        '###############',
        '#S    #   #   #',
        '# ### # # # # #',
        '#   #   # # # #',
        '### # ### # # #',
        '#   #   #   # #',
        '# ##### ##### #',
        '# #   #     # #',
        '# # # # ### # #',
        '#   #   * #  E#',
        '###############',
      ],
    },
    {
      label: 'Level 5', rows: 13, cols: 17,
      grid: [
        '#################',
        '#S#   #   #   # #',
        '# # # # # # # # #',
        '#   #   #   # # #',
        '### ##### ### # #',
        '#   #   #   # # #',
        '# ### # # ### # #',
        '#   # #   #   # #',
        '# # # ##### ### #',
        '# #   #   #   # #',
        '# ##### # # ### #',
        '#       * #     E',
        '#################',
      ],
    },
  ];

  const parseLevel = (lvl) => {
    const rows = [];
    for (let r = 0; r < lvl.rows; r++) {
      const row = [];
      for (let c = 0; c < lvl.cols; c++) {
        row.push(lvl.grid[r]?.[c] ?? '#');
      }
      rows.push(row);
    }
    // find start
    let startR = 0, startC = 0;
    for (let r = 0; r < lvl.rows; r++)
      for (let c = 0; c < lvl.cols; c++)
        if (lvl.grid[r]?.[c] === 'S') { startR = r; startC = c; }
    // find stars
    const stars = [];
    for (let r = 0; r < lvl.rows; r++)
      for (let c = 0; c < lvl.cols; c++)
        if (lvl.grid[r]?.[c] === '*') stars.push(`${r},${c}`);
    return { rows, startR, startC, stars };
  };

  const [levelIdx, setLevelIdx]       = React.useState(0);
  const [screen, setScreen]           = React.useState('menu');
  const [playerR, setPlayerR]         = React.useState(0);
  const [playerC, setPlayerC]         = React.useState(0);
  const [collected, setCollected]     = React.useState(new Set());
  const [moves, setMoves]             = React.useState(0);
  const [won, setWon]                 = React.useState(false);
  const [bump, setBump]               = React.useState(false);
  const [trail, setTrail]             = React.useState([]); // visited cells
  const touchStart = React.useRef(null);

  // Auto-save the move count to the leaderboard on each maze completion
  // (fewer moves is better — see lowerIsBetter in games.jsx).
  useReportScore(won ? moves : 0);

  const lvl = LEVELS[levelIdx];
  const { rows, startR, startC, stars } = React.useMemo(() => parseLevel(lvl), [levelIdx]);

  const startLevel = (idx) => {
    const l = LEVELS[idx];
    const parsed = parseLevel(l);
    setLevelIdx(idx);
    setPlayerR(parsed.startR);
    setPlayerC(parsed.startC);
    setCollected(new Set());
    setMoves(0);
    setWon(false);
    setTrail([`${parsed.startR},${parsed.startC}`]);
    setScreen('play');
  };

  const cell = (r, c) => lvl.grid[r]?.[c] ?? '#';
  const isWalkable = (r, c) => cell(r, c) !== '#';

  const move = (dr, dc) => {
    if (won) return;
    const nr = playerR + dr;
    const nc = playerC + dc;
    if (!isWalkable(nr, nc)) {
      setBump(true);
      setTimeout(() => setBump(false), 300);
      return;
    }
    setPlayerR(nr);
    setPlayerC(nc);
    setMoves(m => m + 1);
    setTrail(t => [...t.slice(-40), `${nr},${nc}`]);
    const key = `${nr},${nc}`;
    if (cell(nr, nc) === '*') setCollected(s => new Set([...s, key]));
    if (cell(nr, nc) === 'E') setWon(true);
  };

  // Keyboard
  React.useEffect(() => {
    if (screen !== 'play') return;
    const onKey = (e) => {
      const map = { ArrowUp:[-1,0], ArrowDown:[1,0], ArrowLeft:[0,-1], ArrowRight:[0,1],
                    w:[-1,0], s:[1,0], a:[0,-1], d:[0,1] };
      const dir = map[e.key];
      if (dir) { e.preventDefault(); move(...dir); }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [screen, playerR, playerC, won]);

  // Touch swipe
  const onTouchStart = (e) => { touchStart.current = { x: e.touches[0].clientX, y: e.touches[0].clientY }; };  const onTouchEnd = (e) => {
    if (!touchStart.current) return;
    const dx = e.changedTouches[0].clientX - touchStart.current.x;
    const dy = e.changedTouches[0].clientY - touchStart.current.y;
    if (Math.abs(dx) < 10 && Math.abs(dy) < 10) return;
    if (Math.abs(dx) > Math.abs(dy)) move(0, dx > 0 ? 1 : -1);
    else move(dy > 0 ? 1 : -1, 0);
    touchStart.current = null;
  };

  // ——— Render ———
  // Responsive cell size — fits the maze to the viewport (no horizontal scroll on phones)
  const [CELL, setCell] = React.useState(36);

  React.useEffect(() => {
    const compute = () => {
      const available = Math.min(window.innerWidth - 32, 720);
      // 17 cols at 18px = 306px (fits a 320px screen with 14px page padding)
      const c = Math.max(18, Math.min(40, Math.floor(available / lvl.cols)));
      setCell(c);
    };
    compute();
    window.addEventListener('resize', compute);
    window.addEventListener('orientationchange', compute);
    return () => {
      window.removeEventListener('resize', compute);
      window.removeEventListener('orientationchange', compute);
    };
  }, [lvl.cols]);

  // ——— Menu ———
  if (screen === 'menu') return (
    <div style={{ display: 'grid', placeItems: 'center', minHeight: 440, padding: '20px 0' }}>
      <div style={{ textAlign: 'center', maxWidth: 480, width: '100%' }}>
        <div style={{ fontSize: 72, marginBottom: 12 }}>🫧</div>
        <h2 style={{ marginBottom: 10 }}>Bubble Maze</h2>
        <p style={{ color: 'var(--ink-soft)', maxWidth: 380, margin: '0 auto 28px' }}>
          Guide the bubble to the exit! Collect the star on the way. Use arrow keys, WASD, swipe, or the on-screen d-pad.
        </p>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))', gap: 12 }}>
          {LEVELS.map((l, i) => (
            <button key={i} className="btn" onClick={() => startLevel(i)}
              style={{ flexDirection: 'column', gap: 4, padding: '14px 10px',
                background: i===0?'var(--c-grass)':i===1?'var(--c-sky)':i===2?'var(--c-sun)':i===3?'var(--c-coral)':'var(--c-grape)',
                color: i>=3 ? 'white' : 'var(--ink)' }}>
              <span style={{ fontSize: 18, fontWeight: 900 }}>{l.label}</span>
              <span style={{ fontSize: 11, opacity: .8 }}>{l.cols - 2}×{l.rows - 2} grid</span>
            </button>
          ))}
        </div>
      </div>
    </div>
  );

  const starsTotal = stars.length;
  const starsGot   = [...collected].filter(k => stars.includes(k)).length;

  // cell size responsive
  const gridW = lvl.cols * CELL;

  return (
    <div onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} style={{ userSelect: 'none' }}>
      {/* Header */}
      <div style={{ display: 'flex', gap: 10, marginBottom: 16, alignItems: 'center', flexWrap: 'wrap' }}>
        <div className="pill-stat">{lvl.label}</div>
        <div className="pill-stat">Moves: {moves}</div>
        {starsTotal > 0 && (
          <div className="pill-stat" style={{ background: starsGot ? 'var(--c-sun)' : undefined }}>
            ⭐ {starsGot}/{starsTotal}
          </div>
        )}
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 8 }}>
          <button className="btn" onClick={() => startLevel(levelIdx)}
            style={{ padding: '8px 14px', fontSize: 13, boxShadow: '3px 3px 0 var(--ink)' }}>↺ Restart</button>
          <button className="btn" onClick={() => setScreen('menu')}
            style={{ padding: '8px 14px', fontSize: 13, boxShadow: '3px 3px 0 var(--ink)' }}>☰ Levels</button>
        </div>
      </div>

      {/* Maze */}
      <div style={{ overflowX: 'auto', overflowY: 'hidden' }}>
        <div style={{
          display: 'grid',
          gridTemplateColumns: `repeat(${lvl.cols}, ${CELL}px)`,
          gridTemplateRows: `repeat(${lvl.rows}, ${CELL}px)`,
          gap: 0,
          border: '3px solid var(--ink)',
          borderRadius: 12,
          overflow: 'hidden',
          width: 'fit-content',
          margin: '0 auto',
          boxShadow: 'var(--shadow-lg)',
          position: 'relative',
        }}>
          {rows.map((row, r) => row.map((ch, c) => {
            const isPlayer = r === playerR && c === playerC;
            const key = `${r},${c}`;
            const isExit = ch === 'E';
            const isStar = ch === '*' && !collected.has(key);
            const isTrail = trail.includes(key) && !isPlayer && ch !== '#';
            const isWall = ch === '#';

            return (
              <div key={key} style={{
                width: CELL, height: CELL,
                background: isWall
                  ? 'var(--ink)'
                  : isExit
                  ? 'oklch(0.75 0.15 145)'
                  : isTrail
                  ? 'oklch(0.88 0.08 230)'
                  : 'white',
                position: 'relative',
                display: 'grid', placeItems: 'center',
                transition: 'background .1s',
              }}>
                {/* Exit flag */}
                {isExit && !isPlayer && (
                  <span style={{ fontSize: CELL * 0.6, lineHeight: 1, filter: 'drop-shadow(1px 1px 0 rgba(0,0,0,.3))' }}>🏁</span>
                )}
                {/* Star */}
                {isStar && (
                  <span style={{ fontSize: CELL * 0.55, lineHeight: 1, animation: 'star-spin 2s linear infinite' }}>⭐</span>
                )}
                {/* Player bubble */}
                {isPlayer && (
                  <div style={{
                    width: CELL * 0.7,
                    height: CELL * 0.7,
                    borderRadius: '50%',
                    background: 'radial-gradient(circle at 35% 35%, oklch(0.88 0.1 230), oklch(0.65 0.16 230))',
                    border: '2.5px solid var(--ink)',
                    boxShadow: bump
                      ? '0 0 0 4px oklch(0.72 0.17 25)'
                      : '2px 3px 0 rgba(0,0,0,.25)',
                    transition: 'box-shadow .15s',
                    position: 'relative',
                    zIndex: 2,
                  }}>
                    {/* Bubble shine */}
                    <div style={{
                      position: 'absolute', top: '18%', left: '22%',
                      width: '28%', height: '20%',
                      background: 'rgba(255,255,255,0.7)',
                      borderRadius: '50%',
                      transform: 'rotate(-30deg)',
                    }}></div>
                  </div>
                )}
              </div>
            );
          }))}
        </div>
      </div>

      {/* On-screen D-pad */}
      <div style={{ display: 'grid', gridTemplateColumns: '52px 52px 52px', gridTemplateRows: '52px 52px 52px',
        gap: 6, margin: '20px auto 0', width: 'fit-content' }}>
        {/* Up */}
        <div></div>
        <button className="btn" onClick={() => move(-1, 0)}
          style={{ padding: 0, placeContent: 'center', fontSize: 22, width: 52, height: 52, borderRadius: 14 }}>▲</button>
        <div></div>
        {/* Left / Down / Right */}
        <button className="btn" onClick={() => move(0, -1)}
          style={{ padding: 0, placeContent: 'center', fontSize: 22, width: 52, height: 52, borderRadius: 14 }}>◀</button>
        <button className="btn" onClick={() => move(1, 0)}
          style={{ padding: 0, placeContent: 'center', fontSize: 22, width: 52, height: 52, borderRadius: 14 }}>▼</button>
        <button className="btn" onClick={() => move(0, 1)}
          style={{ padding: 0, placeContent: 'center', fontSize: 22, width: 52, height: 52, borderRadius: 14 }}>▶</button>
      </div>

      {/* Win overlay */}
      {won && (
        <div style={{
          position: 'fixed', inset: 0, background: 'rgba(27,24,64,.55)',
          display: 'grid', placeItems: 'center', zIndex: 200,
        }}>
          <div style={{
            background: 'var(--paper)', border: 'var(--border-thick)',
            borderRadius: 28, padding: '40px 48px', textAlign: 'center',
            boxShadow: 'var(--shadow-lg)', maxWidth: 380, width: '90%',
          }}>
            <div style={{ fontSize: 72 }}>{starsGot === starsTotal ? '🏆' : '🎉'}</div>
            <h2 style={{ marginTop: 10 }}>
              {starsGot === starsTotal ? 'Perfect run!' : 'You escaped!'}
            </h2>
            <p style={{ color: 'var(--ink-soft)', marginTop: 8 }}>
              {moves} moves · {starsGot}/{starsTotal} stars
            </p>
            <div style={{ display: 'flex', gap: 10, justifyContent: 'center', marginTop: 20, flexWrap: 'wrap' }}>
              <button className="btn btn-green" onClick={() => startLevel(levelIdx)}>↺ Replay</button>
              {levelIdx < LEVELS.length - 1 && (
                <button className="btn btn-primary" onClick={() => startLevel(levelIdx + 1)}>Next level →</button>
              )}
              <button className="btn" onClick={() => setScreen('menu')}>All levels</button>
            </div>
          </div>
        </div>
      )}

      <style>{`
        @keyframes star-spin {
          0%   { transform: rotate(0deg) scale(1); }
          50%  { transform: rotate(180deg) scale(1.15); }
          100% { transform: rotate(360deg) scale(1); }
        }
      `}</style>
    </div>
  );
}

Object.assign(window, { BubbleMazeGame });
