// Globe — wireframe sphere of data "meridians" that deforms around cursor.
// Built with pure SVG. Meridians and parallels are projected 3D lines
// that the cursor warps via a soft displacement field.

const Globe = () => {
  const svgRef = useRef(null);
  const t = useTweaks();
  const motion = t.motion !== false;
  const intensity = t.intensity ?? 1;

  const [, force] = useState(0);
  useEffect(() => {
    if (!motion) return;
    let raf;
    let rot = 0;
    const loop = () => {
      rot += 0.15;
      svgRef.current?.style.setProperty('--rot', `${rot}deg`);
      // re-render displacement each frame
      force((n) => (n + 1) % 1e6);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [motion]);

  // Generate meridians (lines of longitude) and parallels (latitude)
  // Project 3D sphere onto 2D, apply cursor displacement
  const size = 560;
  const c = size / 2;
  const R = 220;

  const render = () => {
    const mouse = window.__mouse__ || { x: window.innerWidth / 2, y: window.innerHeight / 2 };
    // cursor relative to globe center (globe is centered in viewport)
    const gcx = window.innerWidth / 2;
    const gcy = window.innerHeight / 2;
    const mx = (mouse.x - gcx);
    const my = (mouse.y - gcy);

    const displace = (x, y) => {
      // push points away from cursor within a radius
      const dx = x - mx;
      const dy = y - my;
      const d = Math.sqrt(dx * dx + dy * dy) || 1;
      const reach = 180;
      if (d > reach) return { x, y };
      const strength = (1 - d / reach) * 26 * intensity;
      return { x: x + (dx / d) * strength, y: y + (dy / d) * strength };
    };

    const meridians = [];
    const nLon = 14;
    const nLat = 28;
    for (let j = 0; j < nLon; j++) {
      const phi = (j / nLon) * Math.PI * 2;
      const pts = [];
      for (let i = 0; i <= nLat; i++) {
        const theta = (i / nLat) * Math.PI - Math.PI / 2;
        let x = R * Math.cos(theta) * Math.cos(phi);
        let y = R * Math.sin(theta);
        let z = R * Math.cos(theta) * Math.sin(phi);
        // hide points behind sphere (we'll use opacity for fake depth)
        const depth = (z + R) / (2 * R); // 0..1 (1 = front)
        const disp = displace(x, y);
        pts.push({ x: disp.x, y: disp.y, depth });
      }
      meridians.push(pts);
    }

    // parallels — rings at fixed latitude
    const parallels = [];
    const nRings = 7;
    const nSeg = 48;
    for (let i = 1; i < nRings; i++) {
      const theta = (i / nRings) * Math.PI - Math.PI / 2;
      const r = R * Math.cos(theta);
      const y0 = R * Math.sin(theta);
      const pts = [];
      for (let s = 0; s <= nSeg; s++) {
        const phi = (s / nSeg) * Math.PI * 2;
        let x = r * Math.cos(phi);
        let y = y0;
        let z = r * Math.sin(phi);
        const depth = (z + R) / (2 * R);
        const disp = displace(x, y);
        pts.push({ x: disp.x, y: disp.y, depth });
      }
      parallels.push(pts);
    }

    return { meridians, parallels };
  };

  const { meridians, parallels } = render();

  const pathFrom = (pts) => pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${(c + p.x).toFixed(1)},${(c + p.y).toFixed(1)}`).join(' ');

  // avg depth per segment for coloring
  const segColor = (d) => {
    // d 0..1, 1 = front (bright), 0 = back (faint)
    const alpha = 0.08 + d * 0.42;
    return `rgba(237, 235, 228, ${alpha})`;
  };

  return (
    <div className="globe-wrap" aria-hidden="true">
      <svg ref={svgRef} viewBox={`0 0 ${size} ${size}`} width="100%" height="100%" style={{ overflow: 'visible' }}>
        <defs>
          <radialGradient id="globeGlow" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor="oklch(0.84 0.1 var(--accent-h))" stopOpacity="0.1" />
            <stop offset="60%" stopColor="oklch(0.84 0.1 var(--accent-h))" stopOpacity="0.04" />
            <stop offset="100%" stopColor="oklch(0.84 0.1 var(--accent-h))" stopOpacity="0" />
          </radialGradient>
        </defs>
        <circle cx={c} cy={c} r={R + 40} fill="url(#globeGlow)" />

        {/* back-side lines (low opacity) */}
        <g opacity="0.45">
          {parallels.map((pts, i) => (
            <path key={`pb${i}`} d={pathFrom(pts)} fill="none" stroke="rgba(237, 235, 228, 0.08)" strokeWidth="0.6" />
          ))}
        </g>

        {/* meridians — split by depth */}
        {meridians.map((pts, j) => {
          // split into front / back based on average depth of segments
          return pts.map((p, i) => {
            if (i === 0) return null;
            const a = pts[i - 1];
            const avgD = (a.depth + p.depth) / 2;
            return (
              <line
                key={`m${j}-${i}`}
                x1={c + a.x} y1={c + a.y}
                x2={c + p.x} y2={c + p.y}
                stroke={segColor(avgD)}
                strokeWidth={0.4 + avgD * 0.6}
              />
            );
          });
        })}

        {/* parallels */}
        {parallels.map((pts, j) =>
          pts.map((p, i) => {
            if (i === 0) return null;
            const a = pts[i - 1];
            const avgD = (a.depth + p.depth) / 2;
            return (
              <line
                key={`pl${j}-${i}`}
                x1={c + a.x} y1={c + a.y}
                x2={c + p.x} y2={c + p.y}
                stroke={segColor(avgD * 0.9)}
                strokeWidth={0.3 + avgD * 0.5}
              />
            );
          })
        )}

        {/* equator — accent */}
        <path
          d={pathFrom(parallels[Math.floor(parallels.length / 2)])}
          fill="none"
          stroke="oklch(0.84 0.1 var(--accent-h))"
          strokeWidth="0.8"
          opacity="0.6"
          style={{ filter: 'drop-shadow(0 0 4px oklch(0.84 0.1 var(--accent-h)))' }}
        />

        {/* poles */}
        <circle cx={c} cy={c - R} r="2" fill="var(--accent)" opacity="0.8" />
        <circle cx={c} cy={c + R} r="2" fill="var(--accent)" opacity="0.4" />

        {/* outer ticks */}
        {Array.from({ length: 72 }).map((_, i) => {
          const a = (i / 72) * Math.PI * 2;
          const r1 = R + 12;
          const r2 = r1 + (i % 6 === 0 ? 8 : 4);
          return (
            <line
              key={`t${i}`}
              x1={c + Math.cos(a) * r1} y1={c + Math.sin(a) * r1}
              x2={c + Math.cos(a) * r2} y2={c + Math.sin(a) * r2}
              stroke={i % 6 === 0 ? 'var(--line-strong)' : 'var(--line)'}
              strokeWidth="0.7"
            />
          );
        })}
      </svg>
    </div>
  );
};

window.Globe = Globe;
