// ak-globe.jsx — Interactive dotted globe in Canvas 2D
// Dark gray fibonacci dots on white, AK red arcs + country labels.
// Drag to rotate, auto-rotate when idle.

const AK_GLOBE = {
  bg:        '#FFFFFF',
  dotDark:   '#3A3A3A',   // AK.gray1
  dotMid:    '#6B6B6B',
  red:       '#E62321',
  redDeep:   '#B81B19',
  ink:       '#0A0A0A',
  gray2:     '#6B6B6B',
};

// Major cities for AK Networks reach narrative
const AK_CITIES = [
  { name: 'Lisboa',    lat:  38.72, lng:  -9.14 },
  { name: 'Madrid',    lat:  40.41, lng:  -3.70 },
  { name: 'London',    lat:  51.51, lng:  -0.13 },
  { name: 'New York',  lat:  40.71, lng: -74.00 },
  { name: 'São Paulo', lat: -23.55, lng: -46.63 },
  { name: 'Dubai',     lat:  25.27, lng:  55.30 },
  { name: 'Singapore', lat:   1.35, lng: 103.82 },
  { name: 'Tokyo',     lat:  35.68, lng: 139.69 },
  { name: 'Sydney',    lat: -33.87, lng: 151.21 },
];

// Convert lat/lng (degrees) to unit-sphere xyz
function llToXYZ(lat, lng) {
  const phi   = (90 - lat) * Math.PI / 180;
  const theta = (lng + 180) * Math.PI / 180;
  return {
    x: -Math.sin(phi) * Math.cos(theta),
    y:  Math.cos(phi),
    z:  Math.sin(phi) * Math.sin(theta),
  };
}

// Rotate xyz by yaw (around Y) then pitch (around X)
function rotate(p, yaw, pitch) {
  // yaw around Y
  const cy = Math.cos(yaw), sy = Math.sin(yaw);
  let x = p.x * cy + p.z * sy;
  let z = -p.x * sy + p.z * cy;
  let y = p.y;
  // pitch around X
  const cp = Math.cos(pitch), sp = Math.sin(pitch);
  const ny = y * cp - z * sp;
  const nz = y * sp + z * cp;
  return { x, y: ny, z: nz };
}

// Slerp on the unit sphere
function slerp(a, b, t) {
  const dot = Math.max(-1, Math.min(1, a.x*b.x + a.y*b.y + a.z*b.z));
  const omega = Math.acos(dot);
  if (omega < 1e-4) return { ...a };
  const so = Math.sin(omega);
  const k1 = Math.sin((1 - t) * omega) / so;
  const k2 = Math.sin(t * omega) / so;
  return {
    x: a.x * k1 + b.x * k2,
    y: a.y * k1 + b.y * k2,
    z: a.z * k1 + b.z * k2,
  };
}

// Generate fibonacci-distributed points on a unit sphere
function fibonacciSphere(n) {
  const pts = [];
  const phi = Math.PI * (Math.sqrt(5) - 1); // golden angle
  for (let i = 0; i < n; i++) {
    const y = 1 - (i / (n - 1)) * 2;            // y from 1 to -1
    const r = Math.sqrt(1 - y * y);
    const theta = phi * i;
    pts.push({ x: Math.cos(theta) * r, y, z: Math.sin(theta) * r });
  }
  return pts;
}

function AKGlobe({ size = 700, dotCount = 1800, autoRotate = true, accent = AK_GLOBE.red }) {
  const canvasRef = React.useRef(null);
  const stateRef = React.useRef({
    yaw: 2.4, pitch: -0.25,
    targetYaw: 2.4, targetPitch: -0.25,
    dragging: false, lastX: 0, lastY: 0,
    arcs: [],   // active arcs
    nextArcAt: 0,
    points: fibonacciSphere(dotCount),
    cities: AK_CITIES.map(c => ({ ...c, ...llToXYZ(c.lat, c.lng) })),
  });

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    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';
    ctx.scale(dpr, dpr);

    const cx = size / 2, cy = size / 2;
    const radius = size * 0.46;

    // Drag handlers
    const onDown = (e) => {
      const s = stateRef.current;
      s.dragging = true;
      const t = e.touches ? e.touches[0] : e;
      s.lastX = t.clientX; s.lastY = t.clientY;
    };
    const onMove = (e) => {
      const s = stateRef.current;
      if (!s.dragging) return;
      const t = e.touches ? e.touches[0] : e;
      const dx = t.clientX - s.lastX;
      const dy = t.clientY - s.lastY;
      s.lastX = t.clientX; s.lastY = t.clientY;
      s.targetYaw   += dx * 0.005;
      s.targetPitch += dy * 0.005;
      s.targetPitch = Math.max(-1.0, Math.min(1.0, s.targetPitch));
      e.preventDefault();
    };
    const onUp = () => { stateRef.current.dragging = false; };

    canvas.addEventListener('mousedown', onDown);
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
    canvas.addEventListener('touchstart', onDown, { passive: true });
    window.addEventListener('touchmove', onMove, { passive: false });
    window.addEventListener('touchend', onUp);

    // Animation loop
    let raf, lastT = performance.now();
    function frame(now) {
      const dt = Math.min(0.05, (now - lastT) / 1000);
      lastT = now;
      const s = stateRef.current;

      // Auto-rotate when idle
      if (autoRotate && !s.dragging) {
        s.targetYaw += dt * 0.18;
      }
      // Smooth toward target
      s.yaw   += (s.targetYaw   - s.yaw)   * Math.min(1, dt * 8);
      s.pitch += (s.targetPitch - s.pitch) * Math.min(1, dt * 8);

      // Spawn arcs periodically
      if (now > s.nextArcAt) {
        const a = s.cities[Math.floor(Math.random() * s.cities.length)];
        let b = s.cities[Math.floor(Math.random() * s.cities.length)];
        while (b === a) b = s.cities[Math.floor(Math.random() * s.cities.length)];
        s.arcs.push({ a, b, t: 0, life: 2.6 + Math.random() * 1.4 });
        s.nextArcAt = now + 600 + Math.random() * 900;
      }

      // Advance arcs
      s.arcs.forEach(arc => { arc.t += dt; });
      s.arcs = s.arcs.filter(arc => arc.t < arc.life);

      // ── Render ─────────────────────────────────────────────────────────
      ctx.clearRect(0, 0, size, size);

      // Soft red glow underneath the sphere for visual weight
      const glow = ctx.createRadialGradient(cx, cy, radius * 0.2, cx, cy, radius * 1.4);
      glow.addColorStop(0, 'rgba(230, 35, 33, 0.06)');
      glow.addColorStop(1, 'rgba(230, 35, 33, 0)');
      ctx.fillStyle = glow;
      ctx.fillRect(0, 0, size, size);

      // Globe dots
      for (let i = 0; i < s.points.length; i++) {
        const r = rotate(s.points[i], s.yaw, s.pitch);
        if (r.z < -0.05) continue; // back-facing — hide
        const px = cx + r.x * radius;
        const py = cy - r.y * radius;
        // Z depth → opacity + size
        const depth = (r.z + 1) / 2;            // 0..1, 1 = front
        const alpha = 0.18 + 0.55 * depth;
        const dotR  = 0.9 + 1.2 * depth;
        ctx.beginPath();
        ctx.fillStyle = `rgba(58,58,58,${alpha})`;
        ctx.arc(px, py, dotR, 0, Math.PI * 2);
        ctx.fill();
      }

      // Subtle outline ring on equator-edge for definition
      ctx.beginPath();
      ctx.strokeStyle = 'rgba(58,58,58,0.08)';
      ctx.lineWidth = 1;
      ctx.arc(cx, cy, radius + 0.5, 0, Math.PI * 2);
      ctx.stroke();

      // Arcs — drawn on top of dots
      ctx.lineCap = 'round';
      s.arcs.forEach(arc => {
        const lifeT = arc.t / arc.life;
        // Arc travels in two phases: head moves 0→1 while tail moves 0→1 with delay
        const headT = Math.min(1, lifeT * 1.6);
        const tailT = Math.max(0, (lifeT - 0.4) * 1.6);

        // Sample the great-circle, lifting it slightly off the sphere for depth
        const STEPS = 48;
        const lift = 0.18; // arc height above unit sphere
        const pts = [];
        for (let k = 0; k <= STEPS; k++) {
          const u = k / STEPS;
          const slp = slerp(arc.a, arc.b, u);
          const h = 1 + Math.sin(u * Math.PI) * lift;
          const wx = slp.x * h, wy = slp.y * h, wz = slp.z * h;
          pts.push(rotate({ x: wx, y: wy, z: wz }, s.yaw, s.pitch));
        }

        // Draw segments only for points where both ends are visible (front of sphere)
        // and within the [tailT, headT] range
        for (let k = 0; k < STEPS; k++) {
          const u0 = k / STEPS, u1 = (k + 1) / STEPS;
          if (u1 < tailT || u0 > headT) continue;
          const p0 = pts[k], p1 = pts[k + 1];
          if (p0.z < -0.1 && p1.z < -0.1) continue;
          const a = cx + p0.x * radius, b = cy - p0.y * radius;
          const c = cx + p1.x * radius, d = cy - p1.y * radius;
          // Fade alpha by life envelope (fade in → out)
          const env = lifeT < 0.15
            ? lifeT / 0.15
            : lifeT > 0.85
              ? (1 - lifeT) / 0.15
              : 1;
          ctx.strokeStyle = `rgba(230,35,33,${(0.55 + 0.35 * ((p0.z + p1.z) * 0.5)) * env})`;
          ctx.lineWidth = 1.5;
          ctx.beginPath();
          ctx.moveTo(a, b);
          ctx.lineTo(c, d);
          ctx.stroke();
        }

        // Pulse marker at the head
        if (headT > 0.04 && headT < 1.0) {
          const idx = Math.floor(headT * STEPS);
          const p = pts[Math.min(idx, STEPS)];
          if (p.z > -0.1) {
            const x = cx + p.x * radius, y = cy - p.y * radius;
            ctx.fillStyle = AK_GLOBE.red;
            ctx.beginPath();
            ctx.arc(x, y, 3.5, 0, Math.PI * 2);
            ctx.fill();
            // ring pulse
            ctx.strokeStyle = `rgba(230,35,33,${0.5 * (1 - headT)})`;
            ctx.lineWidth = 1.5;
            ctx.beginPath();
            ctx.arc(x, y, 3.5 + headT * 14, 0, Math.PI * 2);
            ctx.stroke();
          }
        }
      });

      // City markers + labels — drawn on top
      ctx.font = '600 12px Helvetica Neue, Arial, sans-serif';
      ctx.textBaseline = 'middle';
      s.cities.forEach(c => {
        const r = rotate(c, s.yaw, s.pitch);
        if (r.z < -0.05) return;
        const px = cx + r.x * radius;
        const py = cy - r.y * radius;
        const depth = (r.z + 1) / 2;
        const alpha = 0.55 + 0.45 * depth;

        // Outer ring
        ctx.strokeStyle = `rgba(230,35,33,${alpha * 0.6})`;
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.arc(px, py, 5, 0, Math.PI * 2);
        ctx.stroke();
        // Inner dot
        ctx.fillStyle = `rgba(230,35,33,${alpha})`;
        ctx.beginPath();
        ctx.arc(px, py, 2.5, 0, Math.PI * 2);
        ctx.fill();

        // Label — only when fairly front-facing
        if (r.z > 0.3) {
          ctx.fillStyle = `rgba(184,27,25,${0.85 * depth})`;
          ctx.fillText(c.name, px + 10, py - 0.5);
        }
      });

      raf = requestAnimationFrame(frame);
    }
    raf = requestAnimationFrame(frame);

    return () => {
      cancelAnimationFrame(raf);
      canvas.removeEventListener('mousedown', onDown);
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
      canvas.removeEventListener('touchstart', onDown);
      window.removeEventListener('touchmove', onMove);
      window.removeEventListener('touchend', onUp);
    };
  }, [size, dotCount, autoRotate]);

  return (
    <canvas
      ref={canvasRef}
      style={{
        cursor: 'grab',
        background: 'transparent',
        userSelect: 'none',
        touchAction: 'none',
      }}
    />
  );
}

window.AKGlobe = AKGlobe;
