// Maison Dahab — Hero3D: real-time gold ring (three.js)
// Physically-shaded 21k gold, soft studio env reflections, cursor tilt,
// slow turntable. Falls back to the photo slider if WebGL is unavailable.
const { useEffect: useH3Effect, useRef: useH3Ref } = React;

function buildEnvScene() {
  // hand-rolled "softbox studio": emissive panels around origin -> PMREM
  const env = new THREE.Scene();
  const panel = (w, h, color, intensity, x, y, z, ry, rx) => {
    const mat = new THREE.MeshBasicMaterial({ color });
    mat.color.multiplyScalar(intensity);
    const m = new THREE.Mesh(new THREE.PlaneGeometry(w, h), mat);
    m.position.set(x, y, z);
    if (ry) m.rotation.y = ry;
    if (rx) m.rotation.x = rx;
    env.add(m);
  };
  env.add(new THREE.Mesh(
    new THREE.SphereGeometry(40, 16, 16),
    new THREE.MeshBasicMaterial({ color: 0x18120a, side: THREE.BackSide })
  ));
  // key softbox — big warm panel upper left
  panel(14, 9, 0xfff1d6, 3.2, -8, 7, 6, Math.PI / 3, -0.4);
  // rim strip — cool-white narrow panel right
  panel(2.5, 12, 0xfff8ee, 4.0, 9, 2, -2, -Math.PI / 2.2, 0);
  // fill — dim warm panel front-low
  panel(10, 4, 0xd9b070, 1.1, 0, -5, 9, 0, 0.5);
  // amber kicker behind
  panel(6, 6, 0xc08a30, 1.4, -2, 1, -10, Math.PI, 0);
  return env;
}

function Hero3D({ onFail }) {
  const hostRef = useH3Ref(null);

  useH3Effect(() => {
    const host = hostRef.current;
    if (!host || !window.THREE) { onFail && onFail(); return; }
    let renderer;
    try {
      renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, powerPreference: "low-power" });
    } catch (e) { onFail && onFail(); return; }

    renderer.setPixelRatio(Math.min(2, window.devicePixelRatio || 1));
    renderer.outputColorSpace = THREE.SRGBColorSpace;
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    renderer.toneMappingExposure = 1.15;
    host.appendChild(renderer.domElement);

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(36, 1, 0.1, 50);
    camera.position.set(0, 0.15, 4.6);

    // environment reflections
    const pmrem = new THREE.PMREMGenerator(renderer);
    const envRT = pmrem.fromScene(buildEnvScene(), 0.06);
    scene.environment = envRT.texture;

    const goldMat = new THREE.MeshStandardMaterial({
      color: 0xe9b95e, metalness: 1.0, roughness: 0.2, envMapIntensity: 1.25,
    });
    const goldMatBrushed = new THREE.MeshStandardMaterial({
      color: 0xd9ab52, metalness: 1.0, roughness: 0.42, envMapIntensity: 1.0,
    });
    const gemMat = new THREE.MeshStandardMaterial({
      color: 0xffffff, metalness: 0.25, roughness: 0.04,
      envMapIntensity: 2.8, flatShading: true,
    });

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

    // main solitaire — standing band
    const ring = new THREE.Group();
    const band = new THREE.Mesh(new THREE.TorusGeometry(1, 0.16, 48, 140), goldMat);
    ring.add(band);
    // crown seat
    const seat = new THREE.Mesh(new THREE.CylinderGeometry(0.2, 0.3, 0.22, 6), goldMat);
    seat.position.set(0, 1.18, 0);
    ring.add(seat);
    // gem — faceted double cone
    const gem = new THREE.Mesh(new THREE.OctahedronGeometry(0.3, 0), gemMat);
    gem.position.set(0, 1.42, 0);
    gem.rotation.y = 0.4;
    ring.add(gem);
    // tiny prongs
    for (let i = 0; i < 4; i++) {
      const a = (i / 4) * Math.PI * 2 + Math.PI / 4;
      const prong = new THREE.Mesh(new THREE.CylinderGeometry(0.025, 0.035, 0.34, 8), goldMat);
      prong.position.set(Math.cos(a) * 0.21, 1.4, Math.sin(a) * 0.21);
      ring.add(prong);
    }
    ring.rotation.z = -0.12;
    group.add(ring);

    // alliance lying behind-left
    const alliance = new THREE.Mesh(new THREE.TorusGeometry(0.78, 0.13, 40, 120), goldMatBrushed);
    alliance.position.set(-1.7, -0.95, -0.6);
    alliance.rotation.set(Math.PI / 2.25, 0.15, 0);
    group.add(alliance);

    // soft shading helpers
    scene.add(new THREE.AmbientLight(0x6a5430, 0.5));
    const dir = new THREE.DirectionalLight(0xfff2da, 1.1);
    dir.position.set(-4, 6, 5);
    scene.add(dir);

    // layout: piece sits right-of-center on wide screens, centered on mobile
    const layout = () => {
      const w = host.clientWidth || 1, h = host.clientHeight || 1;
      renderer.setSize(w, h);
      camera.aspect = w / h;
      camera.updateProjectionMatrix();
      const wide = w / h > 1.15;
      group.position.x = wide ? 1.35 : 0;
      group.position.y = wide ? -0.05 : 0.35;
      const s = wide ? 1 : 0.78;
      group.scale.set(s, s, s);
    };
    layout();
    const ro = new ResizeObserver(layout);
    ro.observe(host);

    // cursor tilt (lerped)
    let tx = 0, ty = 0, cx = 0, cy = 0;
    const onMove = (e) => {
      const r = host.getBoundingClientRect();
      tx = ((e.clientX - r.left) / r.width - 0.5) * 2;
      ty = ((e.clientY - r.top) / r.height - 0.5) * 2;
    };
    const heroEl = host.closest(".hero") || host;
    heroEl.addEventListener("mousemove", onMove);

    const reduced = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const clock = new THREE.Clock();
    let t = 2.2; // start at a flattering angle
    let raf = 0;
    const tick = () => {
      raf = requestAnimationFrame(tick);
      if (document.hidden) return;
      const dt = Math.min(0.05, clock.getDelta());
      const motionOff = reduced || document.documentElement.getAttribute("data-motion") === "off" ||
        document.documentElement.hasAttribute("data-anim-frozen");
      if (!motionOff) {
        t += dt;
        cx += (tx - cx) * 0.04;
        cy += (ty - cy) * 0.04;
      }
      ring.rotation.y = t * 0.4;
      ring.position.y = Math.sin(t * 0.8) * 0.06;
      gem.rotation.y = t * 0.55;
      alliance.rotation.z = t * 0.12;
      group.rotation.y = cx * 0.22;
      group.rotation.x = cy * 0.12;
      renderer.render(scene, camera);
    };
    raf = requestAnimationFrame(tick);

    return () => {
      cancelAnimationFrame(raf);
      ro.disconnect();
      heroEl.removeEventListener("mousemove", onMove);
      envRT.dispose();
      pmrem.dispose();
      scene.traverse((o) => {
        if (o.geometry) o.geometry.dispose();
        if (o.material) o.material.dispose();
      });
      renderer.dispose();
      if (renderer.domElement.parentNode) renderer.domElement.parentNode.removeChild(renderer.domElement);
    };
  }, []);

  return <div className="hero3d" ref={hostRef} aria-hidden="true"></div>;
}

Object.assign(window, { Hero3D });
