// octanex — фирменный wireframe-глобус (из хендоффа Claude Design).
// Адаптировано под панель: глобальный React + регистрация в window (без import/export).
const { useRef: _oxUseRef, useEffect: _oxUseEffect } = React;

const OX_GLOBE_NODES = [
  [55.8, 37.6],   // москва
  [25.2, 55.3],   // дубай
  [40.7, -74.0],  // нью-йорк
  [1.35, 103.8],  // сингапур
];
const OX_BUCKETS = 12;
const OX_ALPHA_BACK = 0.09;
const OX_ALPHA_FRONT = 0.36;
const _oxSmooth = (z) => {
  const t = Math.min(1, Math.max(0, (z + 0.35) / 0.7));
  return t * t * (3 - 2 * t);
};

function OctanexGlobe({ size = 420, speed = 0.18, tilt = 23.5, opacity = 1, nodes = true, meridians = 12, parallels = 9, style }) {
  const ref = _oxUseRef(null);
  _oxUseEffect(() => {
    const canvas = ref.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;
    ctx.scale(dpr, dpr);
    const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    const cx = size / 2, cy = size / 2, R = size * 0.46;
    const tr = (tilt * Math.PI) / 180;
    const cosT = Math.cos(tr), sinT = Math.sin(tr);
    let rot = 0.6, raf = 0, last = performance.now();

    const proj = (phi, lam) => {
      const cp = Math.cos(phi);
      const x = cp * Math.sin(lam + rot);
      const y0 = Math.sin(phi);
      const z = cp * Math.cos(lam + rot);
      return { x: cx + R * (x * cosT - y0 * sinT), y: cy - R * (x * sinT + y0 * cosT), z };
    };

    const draw = () => {
      ctx.clearRect(0, 0, size, size);
      ctx.lineWidth = 1;
      ctx.beginPath();
      ctx.arc(cx, cy, R, 0, Math.PI * 2);
      ctx.strokeStyle = 'rgba(55, 240, 139, 0.22)';
      ctx.stroke();

      const STEP = Math.PI / 60;
      const lines = [];
      for (let m = 0; m < meridians; m++) {
        const lam = (m * 2 * Math.PI) / meridians;
        const line = [];
        for (let phi = -Math.PI / 2; phi <= Math.PI / 2 + 1e-6; phi += STEP) line.push(proj(phi, lam));
        lines.push(line);
      }
      for (let k = 1; k <= parallels; k++) {
        const phi = -Math.PI / 2 + (k * Math.PI) / (parallels + 1);
        const line = [];
        for (let lam = 0; lam <= Math.PI * 2 + 1e-6; lam += STEP) line.push(proj(phi, lam));
        lines.push(line);
      }

      const paths = Array.from({ length: OX_BUCKETS }, () => new Path2D());
      for (const line of lines) {
        for (let i = 1; i < line.length; i++) {
          const a = line[i - 1], b = line[i];
          const t = _oxSmooth((a.z + b.z) / 2);
          const idx = Math.min(OX_BUCKETS - 1, Math.floor(t * OX_BUCKETS));
          paths[idx].moveTo(a.x, a.y);
          paths[idx].lineTo(b.x, b.y);
        }
      }
      for (let i = 0; i < OX_BUCKETS; i++) {
        const t = (i + 0.5) / OX_BUCKETS;
        ctx.strokeStyle = `rgba(55, 240, 139, ${(OX_ALPHA_BACK + t * (OX_ALPHA_FRONT - OX_ALPHA_BACK)).toFixed(3)})`;
        ctx.stroke(paths[i]);
      }

      if (nodes) {
        const time = performance.now() / 1000;
        OX_GLOBE_NODES.forEach(([la, lo], i) => {
          const p = proj((la * Math.PI) / 180, (lo * Math.PI) / 180);
          const vis = Math.min(1, Math.max(0, (p.z + 0.05) / 0.3));
          if (vis <= 0.01) return;
          const r = 2 + Math.sin(time * 2.2 + i * 1.7) * 0.7;
          ctx.beginPath();
          ctx.arc(p.x, p.y, r, 0, Math.PI * 2);
          ctx.fillStyle = `rgba(55, 240, 139, ${(0.9 * vis).toFixed(3)})`;
          ctx.fill();
          ctx.beginPath();
          ctx.arc(p.x, p.y, r + 3.5, 0, Math.PI * 2);
          ctx.strokeStyle = `rgba(55, 240, 139, ${(0.25 * vis).toFixed(3)})`;
          ctx.stroke();
        });
      }
    };

    const loop = (now) => {
      const dt = Math.min((now - last) / 1000, 0.05);
      last = now;
      rot += speed * dt;
      draw();
      raf = requestAnimationFrame(loop);
    };
    if (reduced) draw();
    else raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [size, speed, tilt, nodes, meridians, parallels, opacity]);

  return (
    <canvas ref={ref} width={size} height={size} aria-hidden="true"
      style={{ width: size, height: size, opacity, display: 'block', ...style }}></canvas>
  );
}

Object.assign(window, { OctanexGlobe });
