// ─── Hero 3D Network ────────────────────────────────────────
// Replaces LiveSafetyFeed in the hero right column. A gently rotating
// glass school at center, surrounded by 6 stakeholder nodes with
// data packets flowing along curved arcs. Institutional B2B palette.

function HeroNetwork() {
  const containerRef = useRef(null);
  const labelsRef = useRef(null);
  const centerLogoRef = useRef(null);
  const [webglFailed, setWebglFailed] = useState(false);

  const nodeDefs = [
    { name: 'PARENTS',       shape: 'sphere'  },
    { name: 'BUSES',         shape: 'capsule' },
    { name: 'IOT GATEWAYS',  shape: 'hex'     },
    { name: 'CLASSROOMS',    shape: 'cube'    },
    { name: 'GRADING',       shape: 'grid'    },
    { name: 'ANALYTICS',     shape: 'bars'    },
    { name: 'PRINCIPAL',     shape: 'plate'   },
  ];

  useEffect(() => {
    if (webglFailed) return;
    if (!window.THREE || !containerRef.current) {
      setWebglFailed(true);
      return;
    }

    // WebGL probe
    try {
      const probe = document.createElement('canvas');
      const ctx = probe.getContext('webgl') || probe.getContext('experimental-webgl');
      if (!ctx) { setWebglFailed(true); return; }
    } catch (e) { setWebglFailed(true); return; }

    const THREE = window.THREE;
    const container = containerRef.current;

    const getSize = () => ({
      w: Math.max(1, container.clientWidth),
      h: Math.max(1, container.clientHeight),
    });

    const scene = new THREE.Scene();
    const { w: w0, h: h0 } = getSize();
    const camera = new THREE.PerspectiveCamera(38, w0 / h0, 0.1, 2000);
    camera.position.set(280, 200, 340);
    camera.lookAt(0, 4, 0);

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setSize(w0, h0);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    container.appendChild(renderer.domElement);
    renderer.domElement.style.display = 'block';

    let ctxLost = false;
    const onContextLost = (e) => { e.preventDefault(); ctxLost = true; setWebglFailed(true); };
    renderer.domElement.addEventListener('webglcontextlost', onContextLost);

    // Lighting — soft institutional
    scene.add(new THREE.AmbientLight(0xffffff, 0.88));
    const keyLight = new THREE.DirectionalLight(0xffffff, 1.15);
    keyLight.position.set(80, 200, 90);
    scene.add(keyLight);
    const fillLight = new THREE.DirectionalLight(0xe2effa, 0.35);
    fillLight.position.set(-120, 60, -60);
    scene.add(fillLight);

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

    // Satellite nodes
    const deepMat = new THREE.MeshStandardMaterial({ color: 0x1a5c97, roughness: 0.35, metalness: 0.25 });
    const haloMat = new THREE.MeshBasicMaterial({ color: 0x1a5c97, transparent: true, opacity: 0.18 });

    const nodes = nodeDefs.map((nd, i) => {
      const angle = (Math.PI * 2 / nodeDefs.length) * i - Math.PI / 6;
      const r = 150;
      const nx = Math.cos(angle) * r;
      const nz = Math.sin(angle) * r;
      const ny = 6 + Math.sin(i * 1.37) * 8;

      const group = new THREE.Group();
      group.position.set(nx, ny, nz);

      campusGroup.add(group);
      return { group, angle, baseY: ny };
    });

    // Arcs + data packets
    const arcs = [];
    const idleLineColor = new THREE.Color(0x1a5c97);
    const activeLineColor = new THREE.Color(0xd97d2b);
    const packetGeo = new THREE.SphereGeometry(1.7, 12, 12);

    nodes.forEach((node) => {
      const a = new THREE.Vector3(0, 0, 0);
      const b = node.group.position.clone();
      const mid = new THREE.Vector3().addVectors(a, b).multiplyScalar(0.5);
      mid.y += 28;

      const curve = new THREE.QuadraticBezierCurve3(a, mid, b);
      const pts = curve.getPoints(56);
      const lineGeo = new THREE.BufferGeometry().setFromPoints(pts);
      const lineMat = new THREE.LineBasicMaterial({ color: idleLineColor.getHex(), transparent: true, opacity: 0.18 });
      const line = new THREE.Line(lineGeo, lineMat);
      campusGroup.add(line);

      const packet = new THREE.Mesh(
        packetGeo,
        new THREE.MeshBasicMaterial({ color: 0xd97d2b })
      );
      campusGroup.add(packet);

      arcs.push({
        curve, line, packet,
        t: Math.random(),
        speed: 0.0022 + Math.random() * 0.003,
      });
    });

    // Reduced motion handling
    const motionMql = window.matchMedia('(prefers-reduced-motion: reduce)');
    let reduceMotion = motionMql.matches;
    const onMotionChange = () => { reduceMotion = motionMql.matches; };
    if (motionMql.addEventListener) motionMql.addEventListener('change', onMotionChange);

    // Resize
    const ro = new ResizeObserver(() => {
      const { w, h } = getSize();
      renderer.setSize(w, h);
      camera.aspect = w / h;
      camera.updateProjectionMatrix();
    });
    ro.observe(container);

    // Pause when offscreen
    let offscreen = false;
    const io = new IntersectionObserver((entries) => {
      offscreen = !entries[0].isIntersecting;
    }, { threshold: 0.05 });
    io.observe(container);

    // Animation loop
    let animId;
    let t0 = 0;
    let activeIdx = 0;
    let activeUntil = performance.now() + 1800;
    const tmpVec = new THREE.Vector3();

    const updateLabels = () => {
      const { w, h } = getSize();
      if (labelsRef.current) {
        const children = labelsRef.current.children;
        nodes.forEach((node, i) => {
          const el = children[i];
          if (!el) return;
          node.group.getWorldPosition(tmpVec);
          tmpVec.project(camera);
          const visible = tmpVec.z > -1 && tmpVec.z < 1;
          const x = (tmpVec.x * 0.5 + 0.5) * w;
          const y = (-tmpVec.y * 0.5 + 0.5) * h;
          el.style.transform = `translate3d(${x}px, ${y}px, 0) translate(-50%, -50%)`;
          el.style.opacity = visible ? '1' : '0';
        });
      }
      if (centerLogoRef.current) {
        tmpVec.set(0, 0, 0);
        campusGroup.localToWorld(tmpVec);
        tmpVec.project(camera);
        const x = (tmpVec.x * 0.5 + 0.5) * w;
        const y = (-tmpVec.y * 0.5 + 0.5) * h;
        centerLogoRef.current.style.transform = `translate3d(${x}px, ${y}px, 0) translate(-50%, -50%)`;
        centerLogoRef.current.style.opacity = '1';
      }
    };

    const animate = () => {
      animId = requestAnimationFrame(animate);
      if (ctxLost || offscreen) return;

      if (!reduceMotion) {
        campusGroup.rotation.y += 0.0008;
        t0 += 0.018;
        campusGroup.position.y = Math.sin(t0) * 3;

        arcs.forEach((arc) => {
          arc.t += arc.speed;
          if (arc.t > 1) arc.t = 0;
          let scale = 1;
          if (arc.t < 0.08) scale = arc.t / 0.08;
          else if (arc.t > 0.92) scale = (1 - arc.t) / 0.08;
          arc.packet.scale.setScalar(Math.max(0.01, scale));
          arc.packet.position.copy(arc.curve.getPoint(arc.t));
        });

        if (performance.now() > activeUntil) {
          arcs[activeIdx].line.material.color.copy(idleLineColor);
          arcs[activeIdx].line.material.opacity = 0.18;
          activeIdx = (activeIdx + 1) % arcs.length;
          arcs[activeIdx].line.material.color.copy(activeLineColor);
          arcs[activeIdx].line.material.opacity = 0.75;
          activeUntil = performance.now() + 1800;
        }
      } else {
        // Reduced-motion: static topology, packets parked mid-arc
        arcs.forEach((arc) => {
          arc.packet.position.copy(arc.curve.getPoint(0.5));
          arc.packet.scale.setScalar(1);
        });
      }

      updateLabels();
      renderer.render(scene, camera);
    };

    animate();

    return () => {
      cancelAnimationFrame(animId);
      ro.disconnect();
      io.disconnect();
      if (motionMql.removeEventListener) motionMql.removeEventListener('change', onMotionChange);
      renderer.domElement.removeEventListener('webglcontextlost', onContextLost);
      try { renderer.dispose(); renderer.forceContextLoss(); } catch (e) {}
      if (container && renderer.domElement.parentNode === container) {
        container.removeChild(renderer.domElement);
      }
    };
  }, [webglFailed]);

  if (webglFailed) return <HeroNetworkFallback nodeDefs={nodeDefs} />;

  return (
    <div style={{
      display: 'flex', flexDirection: 'column', alignItems: 'center',
      gap: 18,
      width: '100%', maxWidth: 520,
      animation: 'fade-up 0.9s 0.2s backwards',
      overflow: 'visible',
    }} className="hero-network-root">

      {/* 3D scene — square, with padding around so labels don't clip */}
      <div style={{
        position: 'relative',
        width: '100%', maxWidth: 480,
        aspectRatio: '1 / 1',
        padding: '28px 40px',   // breathing room for labels that extend past the canvas
        boxSizing: 'border-box',
        overflow: 'visible',
      }}>
        {/* Canvas (inset by padding) */}
        <div ref={containerRef} style={{ position: 'absolute', top: 28, left: 40, right: 40, bottom: 28 }} />

        {/* Center logo — projected to scene origin */}
        <div
          ref={centerLogoRef}
          style={{
            position: 'absolute', top: 28, left: 40,
            width: 68, height: 68,
            pointerEvents: 'none',
            filter: 'drop-shadow(0 8px 20px rgba(13,21,48,0.18))',
            willChange: 'transform',
            opacity: 0,
            transition: 'opacity 0.35s ease',
          }}
        >
          <img
            src="assets/Dashboard_Logo_192.png"
            alt="EduGuard"
            style={{ width: '100%', height: '100%', display: 'block' }}
          />
        </div>

        {/* Label overlay — same offset as canvas so label coords match */}
        <div ref={labelsRef} style={{ position: 'absolute', top: 28, left: 40, right: 40, bottom: 28, pointerEvents: 'none', overflow: 'visible' }}>
        {nodeDefs.map((nd, i) => (
          <div
            key={nd.name}
            style={{
              position: 'absolute', top: 0, left: 0,
              display: 'inline-flex', alignItems: 'center', gap: 7,
              padding: '6px 12px',
              background: 'rgba(255,255,255,0.82)',
              backdropFilter: 'blur(12px) saturate(1.2)',
              WebkitBackdropFilter: 'blur(12px) saturate(1.2)',
              borderRadius: 100,
              border: '1px solid rgba(255,255,255,0.6)',
              boxShadow: '0 6px 18px rgba(13,21,48,0.08)',
              fontFamily: 'var(--font-mono)',
              fontSize: 10,
              letterSpacing: '0.12em',
              textTransform: 'uppercase',
              color: 'var(--ink-1)',
              fontWeight: 600,
              whiteSpace: 'nowrap',
              opacity: 0,
              transition: 'opacity 0.25s ease',
              willChange: 'transform',
            }}
          >
            <span style={{
              width: 6, height: 6, borderRadius: '50%',
              background: 'var(--brand)',
            }} />
            {nd.name}
          </div>
        ))}
      </div>
    </div>
    </div>
  );
}

// Static SVG fallback — no WebGL, but preserves the network story
function HeroNetworkFallback({ nodeDefs }) {
  const cx = 250, cy = 250;
  const r = 140;
  const nodePts = nodeDefs.map((nd, i) => {
    const a = (Math.PI * 2 / nodeDefs.length) * i - Math.PI / 2;
    return { ...nd, x: cx + Math.cos(a) * r, y: cy + Math.sin(a) * r * 0.72 };
  });

  return (
    <div style={{ position: 'relative', width: '100%', maxWidth: 320, aspectRatio: '1 / 1' }}>
      <svg viewBox="0 0 500 500" style={{ width: '100%', height: '100%' }}>
        {/* Arcs */}
        {nodePts.map((n, i) => (
          <path
            key={i}
            d={`M ${cx} ${cy} Q ${(cx + n.x) / 2} ${Math.min(cy, n.y) - 50} ${n.x} ${n.y}`}
            fill="none"
            stroke={i === 0 ? '#d97d2b' : '#0d1530'}
            strokeOpacity={i === 0 ? 0.7 : 0.22}
            strokeWidth="1.2"
            strokeDasharray={i === 0 ? '' : '3 4'}
          />
        ))}

      </svg>

      {/* Center logo */}
      <img
        src="assets/Dashboard_Logo_192.png"
        alt="EduGuard"
        style={{
          position: 'absolute', top: '50%', left: '50%',
          transform: 'translate(-50%, -50%)',
          width: 72, height: 72,
          filter: 'drop-shadow(0 8px 20px rgba(13,21,48,0.18))',
        }}
      />

      {/* Labels */}
      {nodePts.map((n, i) => (
        <div key={n.name} style={{
          position: 'absolute',
          left: `${(n.x / 500) * 100}%`,
          top: `${(n.y / 500) * 100}%`,
          transform: 'translate(-50%, -50%)',
          display: 'inline-flex', alignItems: 'center', gap: 7,
          padding: '6px 12px',
          background: 'rgba(255,255,255,0.85)',
          backdropFilter: 'blur(10px)',
          borderRadius: 100,
          border: '1px solid rgba(255,255,255,0.6)',
          boxShadow: '0 6px 18px rgba(13,21,48,0.08)',
          fontFamily: 'var(--font-mono)', fontSize: 10, fontWeight: 600,
          letterSpacing: '0.12em', textTransform: 'uppercase', color: 'var(--ink-1)',
          whiteSpace: 'nowrap',
        }}>
          <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--brand)' }} />
          {n.name}
        </div>
      ))}

    </div>
  );
}

Object.assign(window, { HeroNetwork });
