// 2048 — sticker-styled mini-game
// Use arrow keys (or buttons) to slide tiles. Matching tiles merge.

function Game2048({ T, F }) {
  const SIZE = 4;
  const empty = () => Array(SIZE).fill(0).map(()=>Array(SIZE).fill(0));

  const [grid, setGrid] = React.useState(() => addTile(addTile(empty())));
  const [score, setScore] = React.useState(0);
  const [add, setAdd] = React.useState(0);
  const [best, setBest] = React.useState(() => Number(localStorage.getItem('sp_2048_best') || 0));
  const [over, setOver] = React.useState(false);

  function rndCell(g) {
    const cells = [];
    for (let r=0;r<SIZE;r++) for (let c=0;c<SIZE;c++) if (g[r][c]===0) cells.push([r,c]);
    if (!cells.length) return null;
    return cells[Math.floor(Math.random()*cells.length)];
  }
  function addTile(g) {
    const cell = rndCell(g);
    if (!cell) return g;
    const ng = g.map(r=>r.slice());
    ng[cell[0]][cell[1]] = Math.random()<0.9 ? 2 : 4;
    return ng;
  }

  function slideRow(row) {
    const filtered = row.filter(v => v !== 0);
    let gained = 0;
    for (let i=0;i<filtered.length-1;i++) {
      if (filtered[i] === filtered[i+1]) {
        filtered[i] *= 2;
        gained += filtered[i];
        filtered.splice(i+1, 1);
      }
    }
    while (filtered.length < SIZE) filtered.push(0);
    return { row: filtered, gained };
  }

  function move(dir) {
    if (over) return;
    let g = grid.map(r=>r.slice());
    let totalGained = 0;
    let changed = false;

    const transpose = (m) => m[0].map((_,c)=>m.map(r=>r[c]));
    const reverseRows = (m) => m.map(r=>r.slice().reverse());

    let work = g;
    if (dir === 'up') work = transpose(g);
    if (dir === 'down') work = reverseRows(transpose(g));
    if (dir === 'right') work = reverseRows(g);

    for (let i=0;i<SIZE;i++) {
      const before = work[i].join(',');
      const { row, gained } = slideRow(work[i]);
      work[i] = row;
      totalGained += gained;
      if (before !== row.join(',')) changed = true;
    }

    if (dir === 'up') work = transpose(work);
    if (dir === 'down') work = transpose(reverseRows(work));
    if (dir === 'right') work = reverseRows(work);

    if (!changed) return;
    work = addTile(work);
    setGrid(work);
    if (totalGained) {
      setScore(s => {
        const ns = s + totalGained;
        if (ns > best) { setBest(ns); localStorage.setItem('sp_2048_best', String(ns)); }
        return ns;
      });
      setAdd(totalGained);
      setTimeout(()=>setAdd(0), 600);
    }
    if (isOver(work)) setOver(true);
  }

  function isOver(g) {
    for (let r=0;r<SIZE;r++) for (let c=0;c<SIZE;c++) {
      if (g[r][c]===0) return false;
      if (c<SIZE-1 && g[r][c]===g[r][c+1]) return false;
      if (r<SIZE-1 && g[r][c]===g[r+1][c]) return false;
    }
    return true;
  }

  function restart() {
    setGrid(addTile(addTile(empty())));
    setScore(0); setOver(false); setAdd(0);
    if (window.__sp_playSound) window.__sp_playSound('pop');
  }

  React.useEffect(() => {
    const onKey = (e) => {
      const map = { ArrowUp:'up', ArrowDown:'down', ArrowLeft:'left', ArrowRight:'right' };
      if (map[e.key]) { e.preventDefault(); move(map[e.key]); }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  });

  // swipe support
  const touchRef = React.useRef(null);
  const onTouchStart = (e) => { const t = e.touches[0]; touchRef.current = { x:t.clientX, y:t.clientY }; };
  const onTouchEnd = (e) => {
    if (!touchRef.current) return;
    const t = e.changedTouches[0];
    const dx = t.clientX - touchRef.current.x, dy = t.clientY - touchRef.current.y;
    if (Math.max(Math.abs(dx), Math.abs(dy)) < 30) return;
    if (Math.abs(dx) > Math.abs(dy)) move(dx>0?'right':'left'); else move(dy>0?'down':'up');
  };

  const tileStyle = (v) => {
    const palette = {
      0: { bg: `${T.ink}10`, color: T.ink, fs: 0 },
      2: { bg: T.bg, color: T.ink, fs: 36 },
      4: { bg: T.tape, color: T.ink, fs: 36 },
      8: { bg: T.accent, color: T.ink, fs: 36 },
      16: { bg: T.accent, color: T.ink, fs: 34 },
      32: { bg: T.accent2, color: '#fff', fs: 34 },
      64: { bg: T.accent2, color: '#fff', fs: 34 },
      128: { bg: T.ink, color: T.bg, fs: 28 },
      256: { bg: T.ink, color: T.accent, fs: 28 },
      512: { bg: T.ink, color: T.accent2, fs: 28 },
      1024: { bg: T.ink, color: T.tape, fs: 22 },
      2048: { bg: T.accent, color: T.ink, fs: 22 },
    };
    return palette[v] || palette[2048];
  };

  return (
    <div style={{margin:'0 32px 56px'}}>
      <div style={{display:'flex', alignItems:'baseline', gap:14, marginBottom: 24, flexWrap:'wrap'}}>
        <h2 style={{fontFamily:F.display, fontWeight:F.dispWt, fontSize:72, margin:0, letterSpacing:'-0.04em'}}>2048</h2>
        <PeelSticker t={T} bg={T.accent2} color="#fff" rotate={-4} fontSize={11}>♥ MINI-GAME</PeelSticker>
        <PeelSticker t={T} bg={T.accent} rotate={3} fontSize={11}>USE ARROW KEYS</PeelSticker>
      </div>

      <ScrapBox t={T} bg={T.bg} rotate={-0.5} hoverable={false} style={{padding:'24px 28px', position:'relative'}}>
        <Tape rotate={-3} color={T.tape} w={120} style={{top:-12, left:'40%'}}/>

        <div style={{display:'grid', gridTemplateColumns:'1fr 1fr auto', gap:16, alignItems:'end', marginBottom: 18}}>
          <div>
            <div style={{fontSize:10, fontWeight:800, letterSpacing:'0.18em', textTransform:'uppercase', opacity:0.55}}>SCORE</div>
            <div style={{fontFamily:F.display, fontWeight:F.dispWt, fontSize:36, color:T.accent, position:'relative'}}>
              {score}
              {add>0 && <span style={{position:'absolute', right:-30, top:-4, fontSize:18, color:T.accent2, animation:'sp-floatup .6s ease-out forwards'}}>+{add}</span>}
            </div>
          </div>
          <div>
            <div style={{fontSize:10, fontWeight:800, letterSpacing:'0.18em', textTransform:'uppercase', opacity:0.55}}>BEST</div>
            <div style={{fontFamily:F.display, fontWeight:F.dispWt, fontSize:36, color:T.ink}}>{best}</div>
          </div>
          <button onClick={restart} style={{
            padding:'10px 18px', background:T.accent, color:T.ink,
            border:`2.5px solid ${T.ink}`, boxShadow:`4px 4px 0 0 ${T.ink}`,
            fontFamily:F.display, fontWeight:F.dispWt, fontSize:13, letterSpacing:'0.06em', textTransform:'uppercase', cursor:'pointer',
          }}>↻ RESTART</button>
        </div>

        <style>{`
          @keyframes sp-floatup { 0%{opacity:1; transform:translateY(0)} 100%{opacity:0; transform:translateY(-30px)} }
          @keyframes sp-pop { 0%{transform:scale(0)} 60%{transform:scale(1.12)} 100%{transform:scale(1)} }
        `}</style>

        <div onTouchStart={onTouchStart} onTouchEnd={onTouchEnd}
          style={{
            position:'relative',
            background: `${T.ink}15`,
            border: `2.5px solid ${T.ink}`,
            padding: 10,
            display:'grid',
            gridTemplateColumns:`repeat(${SIZE}, 1fr)`,
            gap: 10,
            aspectRatio: '1/1',
            maxWidth: 480,
            margin:'0 auto',
        }}>
          {grid.flatMap((row, r) => row.map((v, c) => {
            const ts = tileStyle(v);
            return (
              <div key={`${r}-${c}`} style={{
                background: ts.bg, color: ts.color,
                border: v ? `2.5px solid ${T.ink}` : `2px dashed ${T.ink}33`,
                boxShadow: v ? `3px 3px 0 0 ${T.ink}` : 'none',
                display:'flex', alignItems:'center', justifyContent:'center',
                fontFamily: F.display, fontWeight: F.dispWt, fontSize: ts.fs, letterSpacing:'-0.02em',
                aspectRatio:'1/1',
                transform: v ? `rotate(${((r+c)%3-1)*1.5}deg)` : 'none',
                animation: v ? 'sp-pop .25s cubic-bezier(.4,1.6,.5,1)' : 'none',
              }} key2={v}>
                {v || ''}
              </div>
            );
          }))}
          {over && (
            <div style={{position:'absolute', inset:0, background:`${T.ink}ee`, color:T.bg, display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:12}}>
              <div style={{fontFamily:F.display, fontWeight:F.dispWt, fontSize:64, letterSpacing:'-0.04em'}}>GAME OVER</div>
              <div style={{fontFamily:F.hand, fontSize:28, color:T.accent}}>final score: {score} 🙈</div>
              <button onClick={restart} style={{
                padding:'12px 22px', background:T.accent, color:T.ink,
                border:`2.5px solid ${T.bg}`, boxShadow:`4px 4px 0 0 ${T.bg}`,
                fontFamily:F.display, fontWeight:F.dispWt, fontSize:14, letterSpacing:'0.06em', textTransform:'uppercase', cursor:'pointer',
              }}>↻ TRY AGAIN</button>
            </div>
          )}
        </div>

        <div style={{textAlign:'center', marginTop:14, fontFamily:F.hand, fontSize:20, color:T.accent2}}>
          ↳ arrow keys (or swipe) — match same numbers, double them, get to 2048 ★
        </div>
      </ScrapBox>
    </div>
  );
}

window.Game2048 = Game2048;
