/* ============================================================
   Crest3D — the hero centerpiece.
   The full 7ANTERA crest rendered as a floating 3D panel in
   WebGL (Three.js): real perspective parallax on mouse move,
   depth-layered embers in front of and behind the badge, and
   a gentle idle float. Falls back to the static crest image
   if WebGL is unavailable or the user prefers reduced motion.
   ============================================================ */
function Crest3D() {
  const wrapRef = React.useRef(null);
  const [is3d, setIs3d] = React.useState(false);

  React.useEffect(() => {
    const THREE = window.THREE;
    const wrap = wrapRef.current;
    const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
    if (!THREE || !wrap || reduce) return;

    let renderer, scene, camera, raf, ro, onMove;
    const targ = { x: 0, y: 0 };

    try {
      const sized = () => Math.max(160, Math.min(wrap.clientWidth, wrap.clientHeight) || 360);

      renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
      renderer.setPixelRatio(Math.min(2, window.devicePixelRatio || 1));
      renderer.setSize(sized(), sized());
      if (THREE.sRGBEncoding) renderer.outputEncoding = THREE.sRGBEncoding;
      wrap.appendChild(renderer.domElement);

      // If the GPU context is ever lost (tab backgrounding, driver reset,
      // window resize on some systems), fall back to the static crest image
      // instead of leaving an empty frame.
      renderer.domElement.addEventListener('webglcontextlost', (e) => {
        e.preventDefault();
        cancelAnimationFrame(raf);
        setIs3d(false);
      }, false);

      scene = new THREE.Scene();
      camera = new THREE.PerspectiveCamera(38, 1, 0.1, 100);
      camera.position.set(0, 0, 8);

      // the crest panel (whole badge, faithful to the art)
      const badge = new THREE.Group();
      scene.add(badge);

      const tex = new THREE.TextureLoader().load('assets/crest.jpg', () => { try { renderer.render(scene, camera); } catch (_) {} });
      if (THREE.sRGBEncoding) tex.encoding = THREE.sRGBEncoding;
      try { tex.anisotropy = renderer.capabilities.getMaxAnisotropy(); } catch (_) {}

      const SIZE = 4.3;
      const plane = new THREE.Mesh(
        new THREE.PlaneGeometry(SIZE, SIZE, 1, 1),
        new THREE.MeshBasicMaterial({ map: tex, transparent: true })
      );
      badge.add(plane);

      // soft gold glow disc behind the badge for depth
      const glowCanvas = document.createElement('canvas');
      glowCanvas.width = glowCanvas.height = 128;
      const gctx = glowCanvas.getContext('2d');
      const grd = gctx.createRadialGradient(64, 64, 4, 64, 64, 64);
      grd.addColorStop(0, 'rgba(245,177,61,0.55)');
      grd.addColorStop(0.5, 'rgba(255,122,26,0.20)');
      grd.addColorStop(1, 'rgba(245,177,61,0)');
      gctx.fillStyle = grd; gctx.fillRect(0, 0, 128, 128);
      const glowTex = new THREE.CanvasTexture(glowCanvas);
      const glow = new THREE.Mesh(
        new THREE.PlaneGeometry(SIZE * 1.7, SIZE * 1.7),
        new THREE.MeshBasicMaterial({ map: glowTex, transparent: true, depthWrite: false, blending: THREE.AdditiveBlending })
      );
      glow.position.z = -1.2;
      badge.add(glow);

      // depth-layered embers (some in front, some behind)
      const N = 120, pos = new Float32Array(N * 3);
      for (let i = 0; i < N; i++) {
        const a = Math.random() * Math.PI * 2, rr = 1.9 + Math.random() * 1.9;
        pos[i * 3] = Math.cos(a) * rr;
        pos[i * 3 + 1] = (Math.random() - 0.5) * 5.6;
        pos[i * 3 + 2] = (Math.random() - 0.4) * 3.4;
      }
      const pg = new THREE.BufferGeometry();
      pg.setAttribute('position', new THREE.BufferAttribute(pos, 3));
      const embers = new THREE.Points(pg, new THREE.PointsMaterial({
        color: 0xf5b13d, size: 0.07, transparent: true, opacity: 0.9, depthWrite: false, blending: THREE.AdditiveBlending,
      }));
      scene.add(embers);

      onMove = (e) => {
        const r = wrap.getBoundingClientRect();
        targ.x = ((e.clientX - r.left) / r.width - 0.5);
        targ.y = ((e.clientY - r.top) / r.height - 0.5);
      };
      window.addEventListener('pointermove', onMove, { passive: true });

      const loop = (ts) => {
        raf = requestAnimationFrame(loop);
        const tt = ts * 0.001;
        const pullX = Math.max(-1, Math.min(1, targ.x)); // cursor pull, clamped
        const pullY = Math.max(-1, Math.min(1, targ.y));
        // a SUBTLE lean toward the cursor — keep the angles small so the flat
        // crest art tilts like a card and never skews into a broken parallelogram
        badge.rotation.y += ((pullX * 0.16 + Math.sin(tt * 0.5) * 0.05) - badge.rotation.y) * 0.05;
        badge.rotation.x += ((-pullY * 0.11 + Math.sin(tt * 0.42) * 0.04) - badge.rotation.x) * 0.05;
        badge.position.x += ((pullX * 0.18) - badge.position.x) * 0.045;
        badge.position.y += ((-pullY * 0.12 + Math.sin(tt * 0.9) * 0.12) - badge.position.y) * 0.045;
        const sc = 1 + Math.sin(tt * 1.3) * 0.015;
        badge.scale.set(sc, sc, sc);
        glow.material.opacity = 0.7 + (Math.sin(tt * 1.1) * 0.5 + 0.5) * 0.4;
        embers.rotation.y -= 0.0018;
        const arr = embers.geometry.attributes.position.array;
        for (let i = 1; i < arr.length; i += 3) { arr[i] += 0.008; if (arr[i] > 2.7) arr[i] = -2.7; }
        embers.geometry.attributes.position.needsUpdate = true;
        renderer.render(scene, camera);
      };
      raf = requestAnimationFrame(loop);
      setIs3d(true);

      const resize = () => { const s = sized(); renderer.setSize(s, s); };
      if (window.ResizeObserver) { ro = new ResizeObserver(resize); ro.observe(wrap); }

      return () => {
        cancelAnimationFrame(raf);
        if (onMove) window.removeEventListener('pointermove', onMove);
        if (ro) ro.disconnect();
        try { renderer.dispose(); } catch (_) {}
        if (renderer.domElement && renderer.domElement.parentNode) renderer.domElement.parentNode.removeChild(renderer.domElement);
      };
    } catch (err) {
      if (renderer && renderer.domElement && renderer.domElement.parentNode) {
        renderer.domElement.parentNode.removeChild(renderer.domElement);
      }
      setIs3d(false);
    }
  }, []);

  return (
    <div className={`crest3d ${is3d ? 'is-3d' : ''}`} ref={wrapRef}>
      <img className="crest3d__fallback" src="assets/crest.jpg" alt="7ANTERA crest" decoding="async" />
    </div>
  );
}
window.Crest3D = Crest3D;
