// Stacked rings — ten rings, one per year of shipping.
// Each ring rotates on its own axis at its own speed, like an orrery.
// Monochrome, low-contrast, calm. No glow.

const { useRef: useRingRef, useEffect: useRingEffect } = React;

function StackedRings({ rings = 10, samplesPerRing = 220, mouseTilt = true }) {
  const canvasRef = useRingRef(null);
  const wrapRef = useRingRef(null);

  useRingEffect(() => {
    const canvas = canvasRef.current;
    const wrap = wrapRef.current;
    if (!canvas || !wrap) return;

    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    let W = 0, H = 0;

    const resize = () => {
      const r = wrap.getBoundingClientRect();
      W = r.width; H = r.height;
      canvas.width = W * dpr;
      canvas.height = H * dpr;
      canvas.style.width = W + 'px';
      canvas.style.height = H + 'px';
    };
    resize();
    window.addEventListener('resize', resize);

    // Each ring: radius, tilt axis (random unit vector), tilt amount,
    // rotation speed, phase offset, line weight, year label index.
    // Newest year = innermost; outermost = oldest (wider rings = more growth).
    const ringDefs = [];
    for (let i = 0; i < rings; i++) {
      const t = i / (rings - 1); // 0..1, inner→outer
      // Inner rings small, outer rings big
      const radius = 0.22 + t * 0.78;
      // Tilt axis — gives each ring a unique 3D orientation
      const ax = Math.cos(i * 1.137) * 0.35;
      const ay = Math.sin(i * 0.913) * 0.18;
      // Each ring tilts a bit differently
      const tiltX = (Math.sin(i * 1.7) * 0.5 - 0.05) * 0.45;
      const tiltZ = (Math.cos(i * 0.93) * 0.5) * 0.35;
      // Speed: outer rings slower (real orbits), inner faster
      const speed = 0.05 + (1 - t) * 0.08;
      // Direction alternates subtly
      const dir = i % 2 === 0 ? 1 : -0.7;
      ringDefs.push({
        radius,
        tiltX,
        tiltZ,
        speed: speed * dir,
        phase: i * 0.7,
        weight: 0.9 + t * 0.6, // outer slightly thicker
        opacity: 0.25 + (1 - Math.abs(t - 0.5) * 1.2) * 0.4,
        i,
      });
    }

    const state = { time: 0, mouse: { x: 0, y: 0, active: false } };

    const onMove = (e) => {
      const r = wrap.getBoundingClientRect();
      state.mouse.x = (e.clientX - r.left) / r.width - 0.5;
      state.mouse.y = (e.clientY - r.top) / r.height - 0.5;
      state.mouse.active = true;
    };
    const onLeave = () => { state.mouse.active = false; };
    wrap.addEventListener('mousemove', onMove);
    wrap.addEventListener('mouseleave', onLeave);

    const ctx = canvas.getContext('2d');
    let raf;
    let last = performance.now();

    // Smoothed mouse tilt
    let tiltLerpX = -0.32, tiltLerpY = 0.10;

    const tick = (now) => {
      try {
      const dt = Math.min((now - last) / 1000, 0.05);
      last = now;
      state.time += dt;

      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.save();
      ctx.scale(dpr, dpr);

      const ccx = W / 2;
      const ccy = H / 2;
      const baseRadius = Math.min(W, H) * 0.42;
      const persp = 1400;

      // DEBUG: draw a reference circle to confirm tick runs
      // ctx.strokeStyle = 'rgba(255,0,0,0.8)';
      // ctx.lineWidth = 2;
      // ctx.beginPath();
      // ctx.arc(ccx, ccy, baseRadius, 0, Math.PI*2);
      // ctx.stroke();

      // Target tilt — subtle response to cursor, otherwise default isometric-ish
      const targetX = mouseTilt && state.mouse.active ? -0.32 - state.mouse.y * 0.25 : -0.32;
      const targetY = mouseTilt && state.mouse.active ? state.mouse.x * 0.30 : 0.10;
      tiltLerpX += (targetX - tiltLerpX) * Math.min(dt * 4, 1);
      tiltLerpY += (targetY - tiltLerpY) * Math.min(dt * 4, 1);

      const camSX = Math.sin(tiltLerpX), camCX = Math.cos(tiltLerpX);
      const camSY = Math.sin(tiltLerpY), camCY = Math.cos(tiltLerpY);

      for (const def of ringDefs) {
        const r = def.radius * baseRadius;
        const angleSpin = state.time * def.speed + def.phase;

        // Ring's own tilt — rotation around X axis only (so each ring is a tilted disc)
        const rsX = Math.sin(def.tiltX), rcX = Math.cos(def.tiltX);

        const pts = [];
        for (let k = 0; k <= samplesPerRing; k++) {
          const a = (k / samplesPerRing) * Math.PI * 2 + angleSpin;
          // Local ring point in XZ plane (so it's a horizontal disc by default)
          let lx = Math.cos(a) * r;
          let ly = 0;
          let lz = Math.sin(a) * r;

          // Ring tilt around X axis
          let y1 = ly * rcX - lz * rsX;
          let z1 = ly * rsX + lz * rcX;
          let x1 = lx;

          // Camera rotate around Y (yaw)
          let x2 = x1 * camCY + z1 * camSY;
          let z2 = -x1 * camSY + z1 * camCY;
          let y2 = y1;

          // Camera rotate around X (pitch)
          let y3 = y2 * camCX - z2 * camSX;
          let z3 = y2 * camSX + z2 * camCX;
          let x3 = x2;

          const ps = persp / (persp - z3);
          const sx = ccx + x3 * ps;
          const sy = ccy + y3 * ps;
          pts.push({ sx, sy, z: z3 });
        }

        // Draw segments. Split into back (dim) and front (bright).
        ctx.lineCap = 'round';
        for (let k = 0; k < pts.length - 1; k++) {
          const a = pts[k], b = pts[k + 1];
          const avgZ = (a.z + b.z) / 2;
          const depth = avgZ / baseRadius;
          const front = (depth + 1) / 2;
          const alpha = def.opacity * (0.20 + front * 0.95);
          const w = def.weight * (0.6 + front * 0.7);
          ctx.strokeStyle = `rgba(245, 245, 247, ${alpha.toFixed(3)})`;
          ctx.lineWidth = w;
          ctx.beginPath();
          ctx.moveTo(a.sx, a.sy);
          ctx.lineTo(b.sx, b.sy);
          ctx.stroke();
        }

        // Marker dot — frontmost point on the ring
        let frontIdx = 0, frontZ = -Infinity;
        for (let k = 0; k < pts.length; k++) {
          if (pts[k].z > frontZ) { frontZ = pts[k].z; frontIdx = k; }
        }
        const m = pts[frontIdx];
        const front = (m.z / baseRadius + 1) / 2;
        const aDot = 0.5 + front * 0.4;
        const sizeDot = 1.6 + front * 1.6;
        ctx.beginPath();
        ctx.arc(m.sx, m.sy, sizeDot * 2.2, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(245, 245, 247, ${(aDot * 0.18).toFixed(3)})`;
        ctx.fill();
        ctx.beginPath();
        ctx.arc(m.sx, m.sy, sizeDot, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(255, 255, 255, ${aDot.toFixed(3)})`;
        ctx.fill();
      }

      // Centre dot
      ctx.beginPath();
      ctx.arc(ccx, ccy, 2.5, 0, Math.PI * 2);
      ctx.fillStyle = 'rgba(255,255,255,0.9)';
      ctx.fill();

      ctx.restore();
      } catch(e) { console.error('rings tick error:', e); window.__ringsErr = e; }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener('resize', resize);
      wrap.removeEventListener('mousemove', onMove);
      wrap.removeEventListener('mouseleave', onLeave);
    };
  }, [rings, samplesPerRing, mouseTilt]);

  return (
    <div
      ref={wrapRef}
      style={{ width: '100%', height: '100%', position: 'relative', cursor: 'crosshair' }}
    >
      <canvas ref={canvasRef} style={{ display: 'block', width: '100%', height: '100%' }} />
    </div>
  );
}

window.StackedRings = StackedRings;
