// GlobeLoader — dot-matrix globe loader for Atlas.
// Animation driven imperatively via requestAnimationFrame + transform updates
// to avoid per-frame React re-renders of hundreds of dots.

function GlobeLoader({ label, fadeOut, retry, onRetry }) {
  var dotsGroupRef = React.useRef(null);
  var citiesGroupRef = React.useRef(null);
  var scatterGroupRef = React.useRef(null);

  // Pre-generate Fibonacci dot cloud (static)
  var dots = React.useMemo(function() {
    var arr = []; var N = 520; var phi = Math.PI * (Math.sqrt(5) - 1);
    for (var i = 0; i < N; i++) {
      var y = 1 - (i / (N - 1)) * 2;
      var rad = Math.sqrt(1 - y * y);
      var theta = phi * i;
      arr.push({
        x: Math.cos(theta) * rad, y: y, z: Math.sin(theta) * rad,
        seed: (i * 1337) % 100,
        scatterAngle: ((i * 1337) % 100) * 0.13,
      });
    }
    return arr;
  }, []);

  var CITIES = React.useMemo(function() { return [
    { lat: 40.7,  lon: -74,   accent: true },
    { lat: 51.5,  lon: -0.1 },
    { lat: 35.7,  lon: 139.7 },
    { lat: -33.9, lon: 151.2 },
    { lat: -23.5, lon: -46.6 },
    { lat: -26.2, lon: 28 },
    { lat: 19.1,  lon: 72.9 },
    { lat: 22.3,  lon: 114.2 },
  ]; }, []);

  var cx = 240, cy = 160, r = 120;

  React.useEffect(function() {
    var start = performance.now();
    var raf;

    function tick(now) {
      var t = (now - start) / 1000;
      var rotation = t * 30;
      var rad = rotation * Math.PI / 180;
      var cosR = Math.cos(rad), sinR = Math.sin(rad);

      // Update each dot's transform
      var children = dotsGroupRef.current ? dotsGroupRef.current.children : null;
      if (children) {
        for (var i = 0; i < dots.length; i++) {
          var d = dots[i];
          var xr = d.x * cosR - d.z * sinR;
          var zr = d.x * sinR + d.z * cosR;

          var appearAt = d.seed * 0.014;
          var prog = Math.max(0, Math.min(1, (t - appearAt) * 1.0));
          var ease = 1 - Math.pow(1 - prog, 3);
          var scatter = (1 - ease) * (1 + d.seed * 0.04);
          var dx = Math.cos(d.scatterAngle) * scatter * 160;
          var dy = Math.sin(d.scatterAngle) * scatter * 160;

          var px = cx + xr * r + dx;
          var py = cy - d.y * r + dy;
          var front = zr > -0.1;
          var depth = (zr + 1) / 2;
          var op = ease * (front ? 0.75 + depth * 0.25 : 0.3);

          var node = children[i];
          node.setAttribute('cx', px.toFixed(2));
          node.setAttribute('cy', py.toFixed(2));
          node.setAttribute('opacity', op.toFixed(3));
          node.setAttribute('r', (front ? 1.3 + depth * 1.5 : 0.8).toFixed(2));
        }
      }

      // Cities
      var cityChildren = citiesGroupRef.current ? citiesGroupRef.current.children : null;
      if (cityChildren) {
        for (var j = 0; j < CITIES.length; j++) {
          var city = CITIES[j];
          var la = city.lat * Math.PI / 180, lo = city.lon * Math.PI / 180;
          var p3x = Math.cos(la) * Math.cos(lo);
          var p3y = Math.sin(la);
          var p3z = Math.cos(la) * Math.sin(lo);
          var cxr = p3x * cosR - p3z * sinR;
          var czr = p3x * sinR + p3z * cosR;
          var cpx = cx + cxr * r;
          var cpy = cy - p3y * r;
          var front2 = czr > 0;
          var appear = Math.max(0, Math.min(1, (t - 1.2 - j * 0.08) * 2.5));
          var pulse = 1 + Math.sin(t * 2.5 + j) * 0.3;

          var g = cityChildren[j];
          if (front2 && appear > 0) {
            g.style.display = '';
            g.setAttribute('opacity', appear.toFixed(3));
            g.setAttribute('transform', 'translate(' + cpx.toFixed(2) + ',' + cpy.toFixed(2) + ')');
            var ring = g.children[0];
            ring.setAttribute('r', (9 * pulse).toFixed(2));
          } else {
            g.style.display = 'none';
          }
        }
      }

      raf = requestAnimationFrame(tick);
    }
    raf = requestAnimationFrame(tick);
    return function() { cancelAnimationFrame(raf); };
  }, [dots, CITIES]);

  return (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 40,
      background: 'var(--bg)',
      display: 'grid', placeItems: 'center',
      opacity: fadeOut ? 0 : 1,
      transition: 'opacity 420ms ease',
      pointerEvents: fadeOut ? 'none' : 'auto',
    }}>
      <div style={{ position: 'relative', width: 560, height: 440, maxWidth: '94vw' }}>
        <svg viewBox="0 0 480 320" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
          <g ref={dotsGroupRef}>
            {dots.map(function(d, i) {
              return <circle key={i} cx={cx} cy={cy} r="0" fill="var(--fg)" opacity="0"/>;
            })}
          </g>
          <g ref={citiesGroupRef}>
            {CITIES.map(function(city, i) {
              var color = city.accent ? 'var(--accent)' : 'var(--fg)';
              return (
                <g key={i} style={{ display: 'none' }}>
                  <circle r="9" fill="none" stroke={color} strokeWidth="1" opacity="0.6"/>
                  <circle r="3.5" fill={color}/>
                </g>
              );
            })}
          </g>
        </svg>

        <div style={{ position: 'absolute', left: 0, right: 0, bottom: 4, textAlign: 'center' }}>
          <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 11, letterSpacing: '0.22em', color: retry ? 'var(--down)' : 'var(--accent)', textTransform: 'uppercase', marginBottom: 12 }}>
            {retry ? '✕ ' : '◉ '}{label || 'LOADING MARKETS'}
          </div>
          <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 28, fontStyle: 'italic', color: 'var(--fg)', lineHeight: 1.25 }}>
            {retry
              ? <>Connection <span style={{ color: 'var(--down)' }}>interrupted</span>.<br/>Retrying soon.</>
              : <>Charting <span style={{ color: 'var(--accent)' }}>every market</span>,<br/>one tick at a time.</>
            }
          </div>
          {retry && onRetry && (
            <button onClick={onRetry} style={{
              marginTop: 18, fontFamily: "'JetBrains Mono', monospace", fontSize: 11,
              letterSpacing: '0.18em', padding: '8px 18px',
              background: 'transparent', color: 'var(--fg)',
              border: '1px solid var(--line)', cursor: 'pointer',
            }}>RETRY NOW</button>
          )}
        </div>
      </div>
    </div>
  );
}

window.GlobeLoader = GlobeLoader;
