// Interactive globe section, Three.js sphere, amber brand color,
// glassy clickable zone cards with bidirectional sync + camera-focus on click.

const HOTSPOTS = [
  { id: 'ukr',  label: 'UKRAINE',          lat: 48.5, lon: 35.0,  prob: 72, delta: '+3.2', horizon: '72H',
    desc: 'Elevated pressure on Kupiansk + Pokrovsk axes. Rail throughput via Rostov-Tikhoretsk −14% WoW.',
    signals: ['OSINT/RU-chat +212%', 'AIS Sea of Azov −18%', 'Sat revisit ×2 TAC-AIR'] },
  { id: 'tw',   label: 'TAIWAN STRAIT',    lat: 24.0, lon: 121.5, prob: 44, delta: '+1.8', horizon: '30D',
    desc: 'PLAAF sortie frequency at Q3-23 highs. Semi shipment anomaly Taichung −2.1%.',
    signals: ['ADS-B PLAAF ×1.4', 'SEMI TW −2.1%', 'PBoC FX defense'] },
  { id: 'ir',   label: 'IRAN / HORMUZ',    lat: 26.5, lon: 56.5,  prob: 61, delta: '+5.4', horizon: '14D',
    desc: 'IRGC Navy fast-boat formations detected. Tanker insurance Hormuz +340bp.',
    signals: ['AIS fast-boat ×2.8', 'Ins. rate +340bp', 'Brent–Dubai +0.62'] },
  { id: 'il',   label: 'ISRAEL / LEVANT',  lat: 32.5, lon: 34.8,  prob: 58, delta: '-1.1', horizon: '30D',
    desc: 'Hezbollah launch cadence normalized. IDF northern logistics stable.',
    signals: ['Launch rate −28%', 'IDF rail stable', 'Sent. drift +0.18'] },
  { id: 've',   label: 'VENEZUELA',        lat: 8.0,  lon: -66.0, prob: 36, delta: '+2.4', horizon: '60D',
    desc: 'PDVSA crude exports +8% pre-snapback. Border-tension with Guyana elevated.',
    signals: ['Crude exp +8%', 'Guyana ADS-B +3σ', 'Sanctions talk +44%'] },
  { id: 'inpk', label: 'INDIA / PAKISTAN', lat: 32.0, lon: 75.0,  prob: 28, delta: '-0.6', horizon: '90D',
    desc: 'LoC incidents below 12-mo mean. Water-sharing track active.',
    signals: ['LoC −22%', 'IW talks active', 'DGMO hotline calm'] },
  { id: 'kr',   label: 'KOREAN PENINSULA', lat: 39.0, lon: 127.0, prob: 41, delta: '+2.9', horizon: '45D',
    desc: 'DPRK missile cadence +3σ. Sinpo sub dry-dock activity confirmed.',
    signals: ['MSL +3σ', 'Sinpo dry-dock', 'RUB–KRW +184%'] },
];

function latLonToXYZ(lat, lon, R) {
  const THREE = window.THREE;
  const phi = (90 - lat) * Math.PI / 180;
  const theta = (lon + 180) * Math.PI / 180;
  return new THREE.Vector3(
    -R * Math.sin(phi) * Math.cos(theta),
    R * Math.cos(phi),
    R * Math.sin(phi) * Math.sin(theta)
  );
}

function InteractiveGlobe() {
  const mountRef = React.useRef(null);
  const stateRef = React.useRef({});
  const [selected, setSelected] = React.useState('ukr');
  const [hovered, setHovered] = React.useState(null);
  const selectedRef = React.useRef('ukr');
  React.useEffect(() => { selectedRef.current = selected; }, [selected]);

  React.useEffect(() => {
    const THREE = window.THREE;
    if (!THREE) {
      console.error('THREE.js not loaded');
      return;
    }
    const mount = mountRef.current;
    if (!mount) return;
    const W = mount.clientWidth;
    const H = mount.clientHeight;

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(38, W / H, 0.1, 1000);
    camera.position.set(0, 0, 16);
    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setPixelRatio(Math.min(2, window.devicePixelRatio));
    renderer.setSize(W, H);
    mount.appendChild(renderer.domElement);

    const amberCSS = getComputedStyle(document.documentElement).getPropertyValue('--amber').trim() || '#e0a458';
    const amberColor = new THREE.Color(amberCSS);
    const ar = Math.round(amberColor.r * 255);
    const ag = Math.round(amberColor.g * 255);
    const ab = Math.round(amberColor.b * 255);

    const globeGroup = new THREE.Group();
    scene.add(globeGroup);

    const R = 5;

    // Build equirect texture with continents + graticule
    const texCanvas = document.createElement('canvas');
    texCanvas.width = 2048; texCanvas.height = 1024;
    const tctx = texCanvas.getContext('2d');
    tctx.fillStyle = '#0b0d12';
    tctx.fillRect(0, 0, texCanvas.width, texCanvas.height);

    const continents = [
      [[34,-10],[34,10],[31,25],[22,36],[12,43],[3,43],[-12,40],[-26,33],[-34,20],[-34,18],[-22,15],[-8,12],[5,3],[12,-16],[22,-17],[32,-8]],
      [[36,-10],[43,-9],[51,-5],[58,-4],[68,5],[71,29],[60,45],[48,48],[42,40],[37,24],[36,-10]],
      [[40,45],[50,60],[60,70],[72,85],[78,100],[77,110],[70,135],[55,142],[45,140],[35,128],[24,122],[20,108],[10,105],[8,98],[15,95],[22,92],[24,88],[22,72],[19,68],[28,55],[34,48],[40,45]],
      [[83,-75],[70,-100],[60,-130],[55,-165],[52,-172],[48,-125],[33,-118],[23,-110],[17,-100],[15,-85],[30,-80],[25,-80],[35,-75],[45,-62],[55,-60],[65,-55],[83,-75]],
      [[12,-72],[10,-60],[2,-50],[-8,-35],[-23,-42],[-35,-55],[-55,-70],[-52,-73],[-35,-72],[-20,-70],[-5,-80],[5,-77],[12,-72]],
      [[-10,140],[-15,145],[-25,153],[-35,150],[-38,145],[-35,138],[-32,118],[-22,114],[-18,125],[-14,130],[-10,140]],
      [[83,-35],[76,-20],[68,-30],[60,-45],[70,-55],[80,-55],[83,-35]],
      [[-5,95],[-8,105],[-8,116],[-10,125],[-8,140],[0,132],[2,117],[5,107],[5,95]],
      [[58,-5],[55,-2],[51,0],[50,-5],[54,-6],[58,-5]],
      [[45,141],[38,140],[33,130],[34,135],[40,142],[45,144],[45,141]],
    ];

    const latLonToTex = (lat, lon) => ({
      x: ((lon + 180) / 360) * texCanvas.width,
      y: ((90 - lat) / 180) * texCanvas.height,
    });

    tctx.fillStyle = `rgba(${ar},${ag},${ab},0.32)`;
    tctx.strokeStyle = `rgba(${ar},${ag},${ab},0.7)`;
    tctx.lineWidth = 1.2;
    continents.forEach(poly => {
      tctx.beginPath();
      poly.forEach(([lat, lon], i) => {
        const p = latLonToTex(lat, lon);
        if (i === 0) tctx.moveTo(p.x, p.y); else tctx.lineTo(p.x, p.y);
      });
      tctx.closePath();
      tctx.fill();
      tctx.stroke();
    });

    tctx.strokeStyle = `rgba(${ar},${ag},${ab},0.1)`;
    tctx.lineWidth = 1;
    for (let lat = -75; lat <= 75; lat += 15) {
      const y = ((90 - lat) / 180) * texCanvas.height;
      tctx.beginPath(); tctx.moveTo(0, y); tctx.lineTo(texCanvas.width, y); tctx.stroke();
    }
    for (let lon = -180; lon <= 180; lon += 15) {
      const x = ((lon + 180) / 360) * texCanvas.width;
      tctx.beginPath(); tctx.moveTo(x, 0); tctx.lineTo(x, texCanvas.height); tctx.stroke();
    }
    tctx.strokeStyle = `rgba(${ar},${ag},${ab},0.22)`;
    tctx.lineWidth = 1.5;
    tctx.beginPath();
    tctx.moveTo(0, texCanvas.height / 2); tctx.lineTo(texCanvas.width, texCanvas.height / 2); tctx.stroke();

    const earthTex = new THREE.CanvasTexture(texCanvas);
    earthTex.anisotropy = 4;

    const earth = new THREE.Mesh(
      new THREE.SphereGeometry(R, 96, 96),
      new THREE.MeshPhongMaterial({
        map: earthTex,
        shininess: 8,
        specular: new THREE.Color(amberCSS).multiplyScalar(0.12),
        emissive: new THREE.Color(amberCSS).multiplyScalar(0.05),
      })
    );
    globeGroup.add(earth);

    const atmoMat = new THREE.ShaderMaterial({
      transparent: true,
      side: THREE.BackSide,
      uniforms: { c: { value: new THREE.Color(amberCSS) } },
      vertexShader: 'varying vec3 vNormal; void main(){ vNormal = normalize(normalMatrix * normal); gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); }',
      fragmentShader: 'uniform vec3 c; varying vec3 vNormal; void main(){ float i = pow(0.75 - dot(vNormal, vec3(0.0,0.0,1.0)), 3.0); gl_FragColor = vec4(c, i * 0.55); }',
    });
    const atmo = new THREE.Mesh(new THREE.SphereGeometry(R * 1.12, 64, 64), atmoMat);
    globeGroup.add(atmo);

    const ring = new THREE.Mesh(
      new THREE.RingGeometry(R * 1.02, R * 1.025, 128),
      new THREE.MeshBasicMaterial({ color: amberCSS, transparent: true, opacity: 0.35, side: THREE.DoubleSide })
    );
    ring.rotation.x = Math.PI / 2;
    scene.add(ring);

    scene.add(new THREE.AmbientLight(0xffffff, 0.55));
    const dir = new THREE.DirectionalLight(amberCSS, 0.9);
    dir.position.set(6, 4, 8);
    scene.add(dir);

    const markers = HOTSPOTS.map(h => {
      const pos = latLonToXYZ(h.lat, h.lon, R * 1.005);
      const g = new THREE.Group();
      g.position.copy(pos);
      g.lookAt(pos.clone().multiplyScalar(2));

      const risk = h.prob;
      const baseColor = risk > 60 ? '#e06a55' : risk > 40 ? amberCSS : '#7ab27a';

      const core = new THREE.Mesh(
        new THREE.SphereGeometry(0.07, 16, 16),
        new THREE.MeshBasicMaterial({ color: baseColor })
      );
      g.add(core);

      const ringMesh = new THREE.Mesh(
        new THREE.RingGeometry(0.12, 0.15, 32),
        new THREE.MeshBasicMaterial({ color: baseColor, transparent: true, opacity: 0.8, side: THREE.DoubleSide })
      );
      g.add(ringMesh);

      const pulse = new THREE.Mesh(
        new THREE.RingGeometry(0.14, 0.17, 32),
        new THREE.MeshBasicMaterial({ color: baseColor, transparent: true, opacity: 0.4, side: THREE.DoubleSide })
      );
      g.add(pulse);

      const pin = new THREE.Mesh(
        new THREE.CylinderGeometry(0.008, 0.008, 0.5, 6),
        new THREE.MeshBasicMaterial({ color: baseColor, transparent: true, opacity: 0.5 })
      );
      pin.position.z = 0.25;
      pin.rotation.x = Math.PI / 2;
      g.add(pin);

      globeGroup.add(g);
      return { ...h, group: g, core, ring: ringMesh, pulse, pin, baseColor, worldPos: pos.clone() };
    });

    let rotY = -0.3, rotX = -0.1;
    let targetRotY = rotY, targetRotX = rotX;
    let autoSpin = true;
    let dragging = false;
    let last = { x: 0, y: 0, startX: 0, startY: 0 };

    const raycaster = new THREE.Raycaster();
    const mouse = new THREE.Vector2();

    const onDown = (e) => {
      dragging = true;
      autoSpin = false;
      const t = e.touches ? e.touches[0] : e;
      last = { x: t.clientX, y: t.clientY, startX: t.clientX, startY: t.clientY };
    };
    const onMove = (e) => {
      if (!dragging) return;
      const t = e.touches ? e.touches[0] : e;
      const dx = t.clientX - last.x, dy = t.clientY - last.y;
      last.x = t.clientX; last.y = t.clientY;
      targetRotY += dx * 0.006;
      targetRotX = Math.max(-1.1, Math.min(1.1, targetRotX + dy * 0.006));
    };
    const onUp = (e) => {
      if (!dragging) return;
      const t = e.changedTouches ? e.changedTouches[0] : e;
      const moved = Math.hypot(t.clientX - last.startX, t.clientY - last.startY);
      dragging = false;
      if (moved < 5) handleClick(t);
    };
    const handleClick = (t) => {
      const rect = renderer.domElement.getBoundingClientRect();
      mouse.x = ((t.clientX - rect.left) / rect.width) * 2 - 1;
      mouse.y = -((t.clientY - rect.top) / rect.height) * 2 + 1;
      raycaster.setFromCamera(mouse, camera);
      const hitObjects = markers.flatMap(m => [m.core, m.ring, m.pulse]);
      const hits = raycaster.intersectObjects(hitObjects, false);
      if (hits.length) {
        const hit = hits[0].object;
        const marker = markers.find(m => m.core === hit || m.ring === hit || m.pulse === hit);
        if (marker) {
          setSelected(marker.id);
          autoSpin = false;
          focusMarker(marker);
        }
      }
    };

    const focusMarker = (marker) => {
      const p = marker.worldPos;
      const lon = Math.atan2(p.x, p.z);
      targetRotY = -lon;
      const lat = Math.asin(p.y / p.length());
      targetRotX = lat;
    };

    stateRef.current.focusById = (id) => {
      const m = markers.find(mm => mm.id === id);
      if (m) { autoSpin = false; focusMarker(m); }
    };

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

    const resize = () => {
      const W2 = mount.clientWidth, H2 = mount.clientHeight;
      renderer.setSize(W2, H2);
      camera.aspect = W2 / H2;
      camera.updateProjectionMatrix();
    };
    window.addEventListener('resize', resize);

    let rafId;
    const tick = () => {
      const t = performance.now() * 0.001;
      if (autoSpin && !dragging) targetRotY += 0.0015;
      rotY += (targetRotY - rotY) * 0.1;
      rotX += (targetRotX - rotX) * 0.1;
      globeGroup.rotation.y = rotY;
      globeGroup.rotation.x = rotX;

      markers.forEach(m => {
        const isSel = m.id === selectedRef.current;
        const s = 1 + Math.sin(t * 2 + m.lat) * 0.25;
        m.pulse.scale.set(s, s, s);
        m.pulse.material.opacity = 0.35 * (2 - s);
        m.core.scale.setScalar(isSel ? 1.8 : 1);
        m.ring.material.opacity = isSel ? 1 : 0.75;
        m.ring.scale.setScalar(isSel ? 1.4 : 1);
        m.pin.material.opacity = isSel ? 0.9 : 0.4;
      });

      renderer.render(scene, camera);
      rafId = requestAnimationFrame(tick);
    };
    tick();

    return () => {
      cancelAnimationFrame(rafId);
      window.removeEventListener('resize', resize);
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('touchmove', onMove);
      window.removeEventListener('mouseup', onUp);
      window.removeEventListener('touchend', onUp);
      renderer.domElement.removeEventListener('mousedown', onDown);
      renderer.domElement.removeEventListener('touchstart', onDown);
      renderer.dispose();
      if (mount.contains(renderer.domElement)) mount.removeChild(renderer.domElement);
    };
  }, []);

  const selectedSpot = HOTSPOTS.find(h => h.id === selected);

  const onCardClick = (id) => {
    setSelected(id);
    if (stateRef.current.focusById) stateRef.current.focusById(id);
  };

  return (
    <div style={{
      border: '1px solid var(--line)',
      background: 'linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%)',
      display: 'grid',
      gridTemplateColumns: '1fr 420px',
      minHeight: 680,
    }}>
      <div style={{ position: 'relative', borderRight: '1px solid var(--line)', overflow: 'hidden' }}>
        <div style={{
          position: 'absolute', top: 20, left: 24, right: 24, zIndex: 5,
          display: 'flex', justifyContent: 'space-between',
          fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.2em',
          textTransform: 'uppercase', color: 'var(--fg-faint)', pointerEvents: 'none',
        }}>
          <span>◆ GLOBE · GEOPOLITICAL RISK</span>
          <span style={{ color: 'var(--amber)' }}>{HOTSPOTS.length} ZONES · LIVE</span>
        </div>
        <div ref={mountRef} style={{ width: '100%', height: '100%', minHeight: 680, cursor: 'grab' }} />
        <div style={{
          position: 'absolute', bottom: 20, left: 24, right: 24, zIndex: 5,
          display: 'flex', justifyContent: 'space-between',
          fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.2em',
          textTransform: 'uppercase', color: 'var(--fg-faint)', pointerEvents: 'none',
        }}>
          <span>DRAG TO ROTATE · CLICK A MARKER</span>
          <span>SELECTED: <span style={{ color: 'var(--amber)' }}>{selectedSpot.label}</span></span>
        </div>
      </div>

      <div style={{
        padding: '24px 20px',
        display: 'grid',
        gridTemplateRows: 'auto 1fr',
        gap: 16,
        background: 'linear-gradient(180deg, rgba(18,21,28,0.4) 0%, rgba(11,13,18,0.6) 100%)',
        backdropFilter: 'blur(8px)',
        overflow: 'hidden',
      }}>
        <div style={{
          border: '1px solid var(--amber)',
          background: 'linear-gradient(135deg, var(--amber-glow) 0%, transparent 100%)',
          backdropFilter: 'blur(12px)',
          padding: '20px 22px',
          position: 'relative',
          overflow: 'hidden',
        }}>
          <div style={{
            fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.25em',
            textTransform: 'uppercase', color: 'var(--fg-faint)',
          }}>
            ZONE · {selectedSpot.id.toUpperCase()} · {selectedSpot.horizon}
          </div>
          <div style={{
            fontFamily: 'var(--mono)', fontSize: 18, letterSpacing: '0.04em',
            color: 'var(--fg)', textTransform: 'uppercase', marginTop: 8,
          }}>
            {selectedSpot.label}
          </div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, marginTop: 12 }}>
            <div style={{
              fontFamily: 'var(--mono)', fontSize: 64, letterSpacing: '-0.03em',
              color: 'var(--amber)', lineHeight: 1, fontWeight: 500, fontVariantNumeric: 'tabular-nums',
            }}>
              {selectedSpot.prob}<span style={{ fontSize: 28, color: 'var(--fg-dim)' }}>%</span>
            </div>
            <div style={{
              fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.15em',
              textTransform: 'uppercase',
              color: selectedSpot.delta.startsWith('-') ? 'var(--ok)' : 'var(--signal)',
            }}>
              {selectedSpot.delta.startsWith('-') ? '▼' : '▲'} {selectedSpot.delta}pp<br/>24H
            </div>
          </div>
          <div style={{
            fontSize: 13, lineHeight: 1.5, color: 'var(--fg-dim)',
            marginTop: 14, paddingTop: 14, borderTop: '1px solid var(--line)',
          }}>
            {selectedSpot.desc}
          </div>
          <div style={{ marginTop: 12, display: 'grid', gap: 4 }}>
            {selectedSpot.signals.map((s, i) => (
              <div key={i} style={{
                fontFamily: 'var(--mono)', fontSize: 11, color: 'var(--fg)',
                display: 'grid', gridTemplateColumns: '14px 1fr', gap: 6,
              }}>
                <span style={{ color: 'var(--amber)' }}>→</span>{s}
              </div>
            ))}
          </div>
        </div>

        <div style={{ display: 'grid', gap: 8, alignContent: 'start', overflowY: 'auto', paddingRight: 4 }}>
          <div style={{
            fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.25em',
            textTransform: 'uppercase', color: 'var(--fg-faint)', marginBottom: 4,
          }}>ALL ZONES · CLICK TO FOCUS</div>
          {HOTSPOTS.map(h => {
            const active = h.id === selected;
            const hov = h.id === hovered;
            const color = h.prob > 60 ? 'var(--signal)' : h.prob > 40 ? 'var(--amber)' : 'var(--ok)';
            return (
              <div
                key={h.id}
                onClick={() => onCardClick(h.id)}
                onMouseEnter={() => setHovered(h.id)}
                onMouseLeave={() => setHovered(null)}
                style={{
                  cursor: 'pointer',
                  padding: '10px 12px',
                  border: `1px solid ${active ? 'var(--amber)' : hov ? 'var(--line-2)' : 'var(--line)'}`,
                  background: active
                    ? 'linear-gradient(90deg, var(--amber-glow) 0%, transparent 100%)'
                    : hov ? 'rgba(255,255,255,0.02)' : 'transparent',
                  backdropFilter: 'blur(6px)',
                  display: 'grid',
                  gridTemplateColumns: '12px 1fr auto',
                  gap: 10,
                  alignItems: 'center',
                  transition: 'all 180ms ease',
                }}
              >
                <span style={{
                  width: 8, height: 8, borderRadius: '50%', background: color,
                  boxShadow: active ? `0 0 10px ${color}` : 'none',
                }} />
                <div>
                  <div style={{
                    fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.08em',
                    color: active ? 'var(--fg)' : 'var(--fg-dim)', textTransform: 'uppercase',
                  }}>{h.label}</div>
                  <div style={{
                    fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.15em',
                    color: 'var(--fg-faint)', textTransform: 'uppercase', marginTop: 2,
                  }}>HZ {h.horizon} · {h.delta.startsWith('-') ? '▼' : '▲'} {h.delta}pp</div>
                </div>
                <div style={{
                  fontFamily: 'var(--mono)', fontSize: 18, letterSpacing: '-0.02em',
                  color: active ? 'var(--amber)' : 'var(--fg)', fontVariantNumeric: 'tabular-nums',
                }}>
                  {h.prob}<span style={{ fontSize: 11, color: 'var(--fg-faint)' }}>%</span>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { InteractiveGlobe });
