/* Continuously orbiting 3D composition — ceramic plates, arcs, gold pill, dust, guide lines.
   Choreography modelled on the reference frames; palette is ZaviFx amber → crimson. */
function HeroScene() {
  const mount = React.useRef(null);
  const [fallback, setFallback] = React.useState(false);
  const reduce = typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  React.useEffect(() => {
    if (reduce || !window.THREE || !mount.current) { setFallback(true); return; }
    const THREE = window.THREE, el = mount.current;
    let w = el.clientWidth, h = el.clientHeight;
    const mobile = w < 760;

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(38, w / h, 0.1, 120);
    const renderer = new THREE.WebGLRenderer({ antialias: !mobile, alpha: true, powerPreference: 'high-performance' });
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, mobile ? 1.4 : 2));
    renderer.setSize(w, h);
    renderer.shadowMap.enabled = !mobile;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    el.appendChild(renderer.domElement);

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

    const ceramic = (extra) => new THREE.MeshStandardMaterial(Object.assign({ color: 0xF2EEEA, roughness: 0.62, metalness: 0.02 }, extra || {}));
    const gold = new THREE.MeshStandardMaterial({ color: 0xF6B93B, roughness: 0.18, metalness: 1, emissive: 0x5a3200, emissiveIntensity: 0.35 });

    /* floating plates */
    const plates = [];
    const plateGeo = new THREE.BoxGeometry(3.1, 0.13, 3.1);
    [[-1.9, -1.15, 0.4, 0.06], [2.15, -0.35, -1.6, -0.10], [0.2, 1.85, -2.4, 0.14]].forEach(([x, y, z, r]) => {
      const m = new THREE.Mesh(plateGeo, ceramic());
      m.position.set(x, y, z); m.rotation.set(r, r * 2.2, r * 0.6);
      m.castShadow = m.receiveShadow = !mobile;
      rig.add(m); plates.push(m);
    });

    /* torus arcs — the signature shapes */
    const arcs = [];
    const arcA = new THREE.Mesh(new THREE.TorusGeometry(1.32, 0.2, mobile ? 18 : 34, mobile ? 60 : 120, Math.PI * 1.35), ceramic());
    arcA.position.set(-0.15, 0.15, 0.1); arcA.rotation.set(1.32, 0.2, 0.5);
    arcA.castShadow = !mobile; rig.add(arcA); arcs.push(arcA);

    const arcB = new THREE.Mesh(new THREE.TorusGeometry(0.86, 0.15, mobile ? 16 : 28, mobile ? 48 : 96, Math.PI * 1.1), ceramic());
    arcB.position.set(1.75, -0.9, 0.9); arcB.rotation.set(0.9, -0.5, -0.8);
    arcB.castShadow = !mobile; rig.add(arcB); arcs.push(arcB);

    const arcC = new THREE.Mesh(new THREE.TorusGeometry(1.05, 0.13, 16, mobile ? 44 : 88, Math.PI * 0.85), ceramic());
    arcC.position.set(-2.1, 0.95, -0.9); arcC.rotation.set(0.4, 0.9, 1.3);
    rig.add(arcC); arcs.push(arcC);

    /* brand sphere — the ZaviFx mark, kept as the focal object */
    const tex = new THREE.TextureLoader().load(window.ASSETS + 'sphere-zavifx-texture.png');
    tex.anisotropy = 8;
    const orbUniforms = {
      uMap: { value: tex },
      uProgress: { value: 0 },
      uPointer: { value: new THREE.Vector2(0, 0) },
      uTime: { value: 0 },
    };
    const orb = new THREE.Mesh(
      new THREE.SphereGeometry(0.62, mobile ? 48 : 110, mobile ? 32 : 72),
      new THREE.ShaderMaterial({
        uniforms: orbUniforms,
        transparent: true,
        vertexShader: [
          'varying vec2 vUv; varying vec3 vN; varying vec3 vV;',
          'void main(){ vUv = uv; vN = normalize(normalMatrix * normal);',
          ' vec4 mv = modelViewMatrix * vec4(position,1.0); vV = normalize(-mv.xyz);',
          ' gl_Position = projectionMatrix * mv; }'
        ].join('\n'),
        fragmentShader: [
          'uniform sampler2D uMap; uniform float uProgress; uniform float uTime; uniform vec2 uPointer;',
          'varying vec2 vUv; varying vec3 vN; varying vec3 vV;',
          'float hash(vec2 p){ return fract(sin(dot(p, vec2(127.1,311.7)))*43758.5453); }',
          'float cellNoise(vec2 p){ vec2 i = floor(p); vec2 f = fract(p); float d = 1.0;',
          '  for(int y=-1;y<=1;y++){ for(int x=-1;x<=1;x++){ vec2 g = vec2(float(x),float(y));',
          '    vec2 o = vec2(hash(i+g), hash(i+g+7.3)); d = min(d, length(g + o - f)); } } return 1.0 - d; }',
          'void main(){',
          '  vec2 par = uPointer * 0.012;',
          '  vec4 base = texture2D(uMap, vUv + par);',
          /* tiled dot field, cell-noise brightness */
          '  vec2 tUv = vec2(vUv.x * 2.0, vUv.y);',
          '  float tiling = 90.0;',
          '  vec2 tiled = mod(tUv * tiling, 2.0) - 1.0;',
          '  float bright = cellNoise(tUv * tiling * 0.5);',
          '  float dist = length(tiled);',
          '  float dot0 = smoothstep(0.52, 0.46, dist) * bright;',
          /* scan band travelling across the depth proxy */
          '  float depth = vUv.y * 0.75 + (vN.z * 0.5 + 0.5) * 0.25;',
          '  float flow = 1.0 - smoothstep(0.0, 0.035, abs(depth - uProgress));',
          '  float band = 1.0 - smoothstep(0.0, 0.10, abs(depth - uProgress));',
          /* brand-warm mask, screen-blended over the wordmark texture */
          '  vec3 hot = vec3(1.00, 0.42, 0.11);',
          '  vec3 mask = hot * dot0 * flow * 3.2;',
          '  vec3 col = 1.0 - (1.0 - base.rgb) * (1.0 - clamp(mask, 0.0, 1.0));',
          '  col += hot * band * 0.12;',
          /* fresnel rim + gentle breathing glow */
          '  float fres = pow(1.0 - max(dot(vN, vV), 0.0), 2.4);',
          '  col += vec3(1.0, 0.62, 0.28) * fres * 0.55;',
          '  col += hot * (0.04 + 0.03 * sin(uTime * 1.6));',
          '  gl_FragColor = vec4(col, 1.0);',
          '}'
        ].join('\n'),
      })
    );
    orb.position.set(0.05, 0.2, 0.15); orb.castShadow = !mobile;
    rig.add(orb);

    const halo = new THREE.Mesh(new THREE.SphereGeometry(0.95, 32, 24), new THREE.MeshBasicMaterial({ color: 0xFF7A2F, transparent: true, opacity: 0.1 }));
    rig.add(halo);

    /* gold pills riding the arcs */
    const pills = [];
    for (let i = 0; i < 3; i++) {
      const p = new THREE.Mesh(new THREE.SphereGeometry(0.115, 24, 18), gold);
      p.scale.set(1, 0.55, 1); p.castShadow = !mobile;
      rig.add(p); pills.push(p);
    }

    /* thin guide lines */
    const lineMat = new THREE.LineBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.13 });
    for (let i = 0; i < 6; i++) {
      const g = new THREE.BufferGeometry().setFromPoints([
        new THREE.Vector3(-9, -2.4 + i * 0.95, -5 + i * 1.4),
        new THREE.Vector3(9, -2.4 + i * 0.95 + (i % 2 ? 1.6 : -1.2), -5 + i * 1.4),
      ]);
      rig.add(new THREE.Line(g, lineMat));
    }

    /* dust */
    const N = mobile ? 300 : 780;
    const pos = new Float32Array(N * 3);
    for (let i = 0; i < N; i++) {
      pos[i * 3] = (Math.random() - 0.5) * 16;
      pos[i * 3 + 1] = (Math.random() - 0.5) * 9;
      pos[i * 3 + 2] = (Math.random() - 0.5) * 12;
    }
    const dg = new THREE.BufferGeometry();
    dg.setAttribute('position', new THREE.BufferAttribute(pos, 3));
    const dust = new THREE.Points(dg, new THREE.PointsMaterial({ color: 0xffc48a, size: 0.026, transparent: true, opacity: 0.55, sizeAttenuation: true }));
    scene.add(dust);

    /* studio lighting with warm bleed */
    scene.add(new THREE.HemisphereLight(0xfff3e6, 0x2a1206, 0.9));
    const key = new THREE.DirectionalLight(0xffffff, 2.6);
    key.position.set(4, 6, 5); key.castShadow = !mobile;
    if (!mobile) { key.shadow.mapSize.set(1024, 1024); key.shadow.radius = 6; }
    scene.add(key);
    const bleedA = new THREE.PointLight(0xFF6B1F, 7, 16); bleedA.position.set(-3.2, -1.1, 2.2); scene.add(bleedA);
    const bleedB = new THREE.PointLight(0xFFC24A, 4.5, 14); bleedB.position.set(2.9, 1.6, 1.4); scene.add(bleedB);
    const bleedC = new THREE.PointLight(0x8FB4FF, 2.2, 14); bleedC.position.set(0.4, -2.6, -3.2); scene.add(bleedC);

    let raf = 0, t = 0, px = 0, py = 0, tx = 0, ty = 0, live = true, scroll = 0;
    const onPointer = (e) => {
      const r = el.getBoundingClientRect();
      tx = ((e.clientX - r.left) / r.width - 0.5);
      ty = ((e.clientY - r.top) / r.height - 0.5);
    };
    if (!mobile) window.addEventListener('pointermove', onPointer);
    const onScroll = () => { scroll = window.scrollY; };
    window.addEventListener('scroll', onScroll, { passive: true });
    const io = new IntersectionObserver(([e]) => { live = e.isIntersecting; }, { threshold: 0.02 });
    io.observe(el);

    const tick = () => {
      raf = requestAnimationFrame(tick);
      if (!live) return;
      t += 0.0042;
      px += (tx - px) * 0.04; py += (ty - py) * 0.04;
      const s = Math.min(scroll / 1000, 1);

      /* continuous camera orbit — the reference's defining move */
      const rad = 7.4 + Math.sin(t * 0.5) * 0.5;
      camera.position.set(
        Math.sin(t * 0.36) * rad * 0.42 + px * 1.5,
        1.5 + Math.sin(t * 0.27) * 0.7 - py * 1.1 - s * 1.4,
        Math.cos(t * 0.36) * rad
      );
      camera.lookAt(0, 0.1 - s * 0.5, 0);

      rig.rotation.y = t * 0.14;
      orb.rotation.y = t * 1.5;
      orbUniforms.uProgress.value = Math.sin(t * 1.9) * 0.5 + 0.5;
      orbUniforms.uTime.value = t * 60;
      orbUniforms.uPointer.value.set(px * 4, py * 4);
      halo.position.copy(orb.position);
      halo.scale.setScalar(1 + Math.sin(t * 1.8) * 0.02);

      plates.forEach((m, i) => {
        m.position.y += Math.sin(t * (0.8 + i * 0.22)) * 0.0016;
        m.rotation.z += 0.0004 * (i % 2 ? 1 : -1);
      });
      arcs.forEach((a, i) => {
        a.rotation.x += 0.0016 * (i % 2 ? 1 : -0.7);
        a.rotation.y += 0.0011;
        a.position.y += Math.sin(t * (1.1 + i * 0.3)) * 0.0014;
      });
      pills.forEach((p, i) => {
        const a = arcs[i], ang = t * (0.9 + i * 0.35) + i * 2.1;
        const R = [1.32, 0.86, 1.05][i];
        const v = new THREE.Vector3(Math.cos(ang) * R, Math.sin(ang) * R, 0).applyEuler(a.rotation).add(a.position);
        p.position.copy(v);
        p.rotation.y = ang;
      });

      dust.rotation.y = -t * 0.28;
      dust.position.y = -s * 0.8;
      renderer.render(scene, camera);
    };
    tick();

    const onResize = () => {
      w = el.clientWidth; h = el.clientHeight;
      camera.aspect = w / h; camera.updateProjectionMatrix(); renderer.setSize(w, h);
    };
    window.addEventListener('resize', onResize);

    return () => {
      cancelAnimationFrame(raf); io.disconnect();
      window.removeEventListener('resize', onResize);
      window.removeEventListener('pointermove', onPointer);
      window.removeEventListener('scroll', onScroll);
      scene.traverse((o) => { if (o.geometry) o.geometry.dispose(); if (o.material) (Array.isArray(o.material) ? o.material : [o.material]).forEach((m) => m.dispose()); });
      tex.dispose(); renderer.dispose();
      if (renderer.domElement.parentNode === el) el.removeChild(renderer.domElement);
    };
  }, [reduce]);

  return (
    <div aria-hidden="true" className="zx-hero__stage zx-hero__stage--full">
      <span className="zx-hero__bloom" />
      {fallback
        ? <img src={window.ASSETS + 'sphere-static.png'} alt="" className="zx-hero__static" />
        : <div ref={mount} className="zx-hero__gl" />}
    </div>
  );
}
Object.assign(window, { HeroScene });
