// pooltable.jsx — minimalist billiards: a cue stick auto-strikes the white ball
// toward a random numbered ball every ~3s; clicking a numbered ball pops up what
// the number represents.

function NumbersPool() {
  const wrapRef = React.useRef(null);
  const ballRefs = React.useRef([]);
  const stickRef = React.useRef(null);
  const stateRef = React.useRef(null);
  const [selected, setSelected] = React.useState(null);

  // index 0 = cue ball (white, no number); rest carry a stat.
  const BALLS = [
    { cue: true, color: '#f4efe4' },
    { n: '1520', label: 'SAT Score',                 color: '#ffd76a' },
    { n: '4',    label: 'Hackathon Wins',            color: '#7ec4f2' },
    { n: '19',   label: 'Age',                        color: '#ff9eb0' },
    { n: '3',    label: 'Instruments Played',         color: '#b79bf0' },
    { n: '900',  label: 'Chess Elo',                  color: '#86dba8' },
    { n: '475',  label: 'Restaurants Ranked on Beli', color: '#ffb077' },
    { n: '138',  label: 'Typing Speed (WPM)',         color: '#5fc9bf' },
    { n: '4',    label: 'Languages Spoken',           color: '#f58a8a' },
  ];
  const R = 16;

  React.useEffect(() => {
    const wrap = wrapRef.current;
    if (!wrap) return;
    let W = wrap.clientWidth, H = wrap.clientHeight;

    const balls = BALLS.map(() => ({ x: 0, y: 0, vx: 0, vy: 0, r: R }));
    balls.forEach((b) => {
      let ok = false, t = 0;
      while (!ok && t < 400) {
        b.x = R + Math.random() * (W - 2 * R);
        b.y = R + Math.random() * (H - 2 * R);
        ok = balls.every((o) => o === b || Math.hypot(o.x - b.x, o.y - b.y) > 2 * R + 6);
        t++;
      }
    });
    stateRef.current = { balls, W, H, strike: { phase: 'idle', start: 0, angle: 0, gap: 0 }, nextAt: performance.now() + 1400 };
    ballRefs.current.forEach((el) => { if (el) { el.style.width = el.style.height = 2 * R + 'px'; } });

    let raf;
    const step = (now) => {
      const st = stateRef.current;
      const balls = st.balls;
      W = st.W; H = st.H;

      for (const b of balls) {
        b.x += b.vx; b.y += b.vy;
        b.vx *= 0.99; b.vy *= 0.99;
        if (Math.hypot(b.vx, b.vy) < 0.05) { b.vx = 0; b.vy = 0; }
        if (b.x < b.r) { b.x = b.r; b.vx = Math.abs(b.vx); }
        if (b.x > W - b.r) { b.x = W - b.r; b.vx = -Math.abs(b.vx); }
        if (b.y < b.r) { b.y = b.r; b.vy = Math.abs(b.vy); }
        if (b.y > H - b.r) { b.y = H - b.r; b.vy = -Math.abs(b.vy); }
      }
      for (let i = 0; i < balls.length; i++) {
        for (let j = i + 1; j < balls.length; j++) {
          const a = balls[i], b = balls[j];
          const dx = b.x - a.x, dy = b.y - a.y;
          const d = Math.hypot(dx, dy), min = a.r + b.r;
          if (d > 0 && d < min) {
            const nx = dx / d, ny = dy / d, ov = (min - d) / 2;
            a.x -= nx * ov; a.y -= ny * ov; b.x += nx * ov; b.y += ny * ov;
            const rel = (b.vx - a.vx) * nx + (b.vy - a.vy) * ny;
            if (rel < 0) { a.vx += rel * nx; a.vy += rel * ny; b.vx -= rel * nx; b.vy -= rel * ny; }
          }
        }
      }

      // ---- cue-stick strike sequence ----
      const cue = balls[0];
      const k = st.strike;
      const cueSp = Math.hypot(cue.vx, cue.vy);
      if (k.phase === 'idle' && now > st.nextAt && cueSp < 0.15) {
        const target = balls[1 + Math.floor(Math.random() * (balls.length - 1))];
        k.angle = Math.atan2(target.y - cue.y, target.x - cue.x);
        k.phase = 'aim'; k.start = now;
      } else if (k.phase === 'aim') {
        const p = Math.min(1, (now - k.start) / 460);
        k.gap = 6 + p * 28;
        if (p >= 1) { k.phase = 'thrust'; k.start = now; }
      } else if (k.phase === 'thrust') {
        const p = Math.min(1, (now - k.start) / 120);
        k.gap = 34 - p * 32;
        if (p >= 1) {
          const s = 4.8;
          cue.vx = Math.cos(k.angle) * s; cue.vy = Math.sin(k.angle) * s;
          k.phase = 'idle'; st.nextAt = now + 3000;
        }
      }
      const stick = stickRef.current;
      if (stick) {
        if (k.phase === 'aim' || k.phase === 'thrust') {
          const deg = (k.angle + Math.PI) * 180 / Math.PI;
          stick.style.opacity = '1';
          stick.style.left = cue.x + 'px';
          stick.style.top = (cue.y - 2.5) + 'px';
          stick.style.transform = 'rotate(' + deg + 'deg) translateX(' + (R + k.gap) + 'px)';
        } else {
          stick.style.opacity = '0';
        }
      }

      balls.forEach((b, i) => {
        const el = ballRefs.current[i];
        if (el) el.style.transform = 'translate(' + (b.x - b.r) + 'px,' + (b.y - b.r) + 'px)';
      });
      raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);

    const ro = new ResizeObserver(() => { const st = stateRef.current; st.W = wrap.clientWidth; st.H = wrap.clientHeight; });
    ro.observe(wrap);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, []);

  return (
    <div className="pool" ref={wrapRef}>
      <div className="pool-brand" aria-hidden="true">Sofi Le</div>
      <span className="pocket tl"></span>
      <span className="pocket tr"></span>
      <span className="pocket bl"></span>
      <span className="pocket br"></span>
      <span className="pocket tm"></span>
      <span className="pocket bm"></span>
      <div className="cue-stick" ref={stickRef} aria-hidden="true"></div>
      {BALLS.map((s, i) =>
        <button
          key={i}
          ref={(el) => (ballRefs.current[i] = el)}
          className={'pball' + (s.cue ? ' cue' : '')}
          style={{ '--ball': s.color }}
          onClick={s.cue ? undefined : () => setSelected(s)}
          aria-label={s.cue ? 'cue ball' : (s.n + ' — ' + s.label)}>
          {!s.cue && <span className="pball-num">{s.n}</span>}
        </button>
      )}
      {selected &&
        <div className="pool-pop" onClick={() => setSelected(null)}>
          <div className="pool-pop-card" onClick={(e) => e.stopPropagation()}>
            <button className="pop-close" onClick={() => setSelected(null)} aria-label="Close">×</button>
            <div className="pop-num">{selected.n}</div>
            <div className="pop-label">{selected.label}</div>
          </div>
        </div>
      }
    </div>);
}

Object.assign(window, { NumbersPool });
