/* ──────────────────────────────────────────────────────────
   DotOrb — particle dot sphere on canvas.
   Cursor tilts the rotation and pushes nearby dots outward.
   ────────────────────────────────────────────────────────── */
const { useState, useEffect, useRef, useMemo, useLayoutEffect } = React;

function DotOrb({ size = 560, particles = 3800 }) {
  const wrapRef = useRef(null);
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    canvas.width = size * dpr;
    canvas.height = size * dpr;
    canvas.style.width = size + 'px';
    canvas.style.height = size + 'px';
    const ctx = canvas.getContext('2d');
    ctx.scale(dpr, dpr);

    const cx = size / 2;
    const cy = size / 2;
    const baseR = size * 0.32; // sphere radius

    // Build particles on a sphere using a Fibonacci lattice
    const pts = [];
    const phi = Math.PI * (3 - Math.sqrt(5));
    for (let i = 0; i < particles; i++) {
      const y = 1 - (i / (particles - 1)) * 2; // -1..1
      const r = Math.sqrt(1 - y * y);
      const theta = phi * i;
      const x = Math.cos(theta) * r;
      const z = Math.sin(theta) * r;
      // assign a colour band based on latitude — some warm gold, some dark
      // gives a subtle "topography" look like the concept image
      const tone = Math.random();
      // Some dots are gold accents (~22%), most are dark ink, a few are very dark
      let color;
      if (tone < 0.18) {
        // gold/champagne accent
        const goldL = 60 + Math.random() * 18;
        color = `hsl(${36 + Math.random()*8}, ${42 + Math.random()*12}%, ${goldL}%)`;
      } else if (tone < 0.55) {
        // dark ink
        color = `rgba(20,24,31,${0.55 + Math.random()*0.30})`;
      } else {
        // medium ink with warm tinge
        color = `rgba(${50 + Math.random()*30},${42 + Math.random()*20},${36 + Math.random()*20},${0.45 + Math.random()*0.30})`;
      }
      pts.push({
        x, y, z,
        // small per-point radial offset for surface texture
        rOff: 1 + (Math.random() - 0.5) * 0.018,
        size: 0.7 + Math.random() * 1.5,
        color,
        // displacement velocity for cursor interaction
        dx: 0, dy: 0, dz: 0,
      });
    }

    // Pointer state
    const mouse = { x: cx, y: cy, inside: false, vx: 0, vy: 0 };
    const onMove = (e) => {
      const r = canvas.getBoundingClientRect();
      const nx = e.clientX - r.left;
      const ny = e.clientY - r.top;
      mouse.x = nx; mouse.y = ny;
      mouse.inside = nx >= 0 && nx <= size && ny >= 0 && ny <= size;
    };
    const onLeave = () => { mouse.inside = false; };
    window.addEventListener('mousemove', onMove);
    canvas.addEventListener('mouseleave', onLeave);

    // Rotation state — base drift + mouse-driven tilt
    let rotY = 0, rotX = 0;
    let tgtRotX = 0, tgtRotY = 0;
    let raf;

    // Sort buffer for back-to-front draw
    const buf = new Array(particles);

    const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    let t0 = performance.now();
    const draw = (t) => {
      const dt = Math.min(0.05, (t - t0) / 1000);
      t0 = t;

      // Mouse drives target rotation
      if (mouse.inside) {
        tgtRotY = ((mouse.x / size) - 0.5) * 1.1;
        tgtRotX = ((mouse.y / size) - 0.5) * -0.7;
      } else {
        // drift idle when mouse outside
        tgtRotY = Math.sin(t * 0.00015) * 0.35;
        tgtRotX = Math.cos(t * 0.0001) * 0.15;
      }
      // Spring toward target
      rotY += (tgtRotY - rotY) * 0.045;
      rotX += (tgtRotX - rotX) * 0.045;
      // Always add a slow auto-rotate so it never feels frozen
      if (!reduced) rotY += dt * 0.08;

      const sinY = Math.sin(rotY), cosY = Math.cos(rotY);
      const sinX = Math.sin(rotX), cosX = Math.cos(rotX);

      ctx.clearRect(0, 0, size, size);

      // Project and update displacement
      for (let i = 0; i < particles; i++) {
        const p = pts[i];
        // Rotate around Y, then X
        const xy = p.x * cosY - p.z * sinY;
        const zy = p.x * sinY + p.z * cosY;
        const y2 = p.y * cosX - zy * sinX;
        const z2 = p.y * sinX + zy * cosX;

        // Surface radius (with per-point bump + cursor outward push)
        let surface = baseR * p.rOff;

        // Project
        const px = cx + xy * surface;
        const py = cy + y2 * surface;
        const depth = (z2 + 1) / 2; // 0 (back) .. 1 (front)

        // Cursor proximity displacement
        if (mouse.inside) {
          const ddx = px - mouse.x;
          const ddy = py - mouse.y;
          const dist = Math.sqrt(ddx*ddx + ddy*ddy);
          const radius = 90;
          if (dist < radius && dist > 0.1) {
            const force = (1 - dist / radius) * 5;
            buf[i] = { px: px + (ddx/dist) * force, py: py + (ddy/dist) * force,
              depth, color: p.color, size: p.size };
            continue;
          }
        }
        buf[i] = { px, py, depth, color: p.color, size: p.size };
      }

      // Sort by depth back-to-front
      buf.sort((a, b) => a.depth - b.depth);

      for (let i = 0; i < particles; i++) {
        const b = buf[i];
        // Fade back-facing dots — sphere is somewhat transparent
        const alpha = 0.18 + b.depth * 0.85;
        const r = b.size * (0.45 + b.depth * 0.85);
        ctx.globalAlpha = Math.min(1, alpha);
        ctx.fillStyle = b.color;
        ctx.beginPath();
        ctx.arc(b.px, b.py, r, 0, Math.PI * 2);
        ctx.fill();
      }
      ctx.globalAlpha = 1;

      raf = requestAnimationFrame(draw);
    };
    raf = requestAnimationFrame(draw);

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener('mousemove', onMove);
      canvas.removeEventListener('mouseleave', onLeave);
    };
  }, [size, particles]);

  return (
    <div ref={wrapRef} style={{ position:'relative', width: size, height: size }}>
      {/* Soft warm radial glow behind orb */}
      <div style={{
        position:'absolute', inset:'-8%', borderRadius:'50%',
        background:'radial-gradient(circle, rgba(184,153,104,0.16) 0%, rgba(184,153,104,0.05) 35%, rgba(184,153,104,0) 60%)',
        pointerEvents:'none', filter:'blur(8px)',
      }} />
      <canvas ref={canvasRef} style={{ position:'relative', display:'block' }} />
      {/* Soft contact shadow */}
      <div style={{
        position:'absolute', bottom:'4%', left:'50%',
        width:'52%', height:'4%', borderRadius:'50%',
        background:'radial-gradient(ellipse, rgba(20,24,31,0.20), rgba(20,24,31,0) 70%)',
        filter:'blur(8px)', transform:'translateX(-50%)',
      }} />
    </div>
  );
}

Object.assign(window, { DotOrb });
