// three-blob.jsx
// Real 3D sphere via Three.js — replaces the CSS .blob-3d placeholder.
// • PBR material (clearcoat + sheen) so it reads as glass/ceramic
// • Slow rotation + idle bobbing
// • Subtle mouse parallax tied to viewport position
// • Reacts to --accent changes (Tweaks panel)

(function() {
  // One-time loader for Three.js if not already on window.
  if (!window.__threeLoaderStarted) {
    window.__threeLoaderStarted = true;
    const s = document.createElement("script");
    s.src = "https://unpkg.com/three@0.160.0/build/three.min.js";
    s.async = false;
    document.head.appendChild(s);
  }
})();

function ThreeBlob({ size = 200, style, animate = true, intensity = 1 }) {
  const ref = React.useRef(null);

  React.useEffect(() => {
    const host = ref.current;
    if (!host) return;
    let raf = 0, disposed = false;
    let renderer, scene, camera, sphere, geo, mat, mouseListener, observer;

    function readAccent() {
      const v = getComputedStyle(document.documentElement).getPropertyValue("--accent").trim();
      return v || "#c44a1f";
    }

    function start() {
      if (disposed || !window.THREE) return;
      const THREE = window.THREE;

      renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
      renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
      renderer.setSize(size, size, false);
      renderer.outputColorSpace = THREE.SRGBColorSpace;
      renderer.toneMapping = THREE.ACESFilmicToneMapping;
      renderer.toneMappingExposure = 1.05;

      // Make the canvas fill the host div
      const canvas = renderer.domElement;
      canvas.style.width = "100%";
      canvas.style.height = "100%";
      canvas.style.display = "block";
      host.appendChild(canvas);

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

      const baseColor = new THREE.Color(readAccent());

      geo = new THREE.SphereGeometry(1, 96, 96);
      mat = new THREE.MeshPhysicalMaterial({
        color: baseColor,
        roughness: 0.32,
        metalness: 0.08,
        clearcoat: 0.7,
        clearcoatRoughness: 0.22,
        sheen: 0.6,
        sheenRoughness: 0.5,
        sheenColor: new THREE.Color("#ffe1c8"),
        reflectivity: 0.4,
      });
      sphere = new THREE.Mesh(geo, mat);
      scene.add(sphere);

      // Three-point lighting for a sculpted, warm-paper-friendly feel
      const key = new THREE.DirectionalLight(0xfff0e0, 2.6 * intensity);
      key.position.set(2.2, 3.2, 3.8);
      scene.add(key);

      const fill = new THREE.DirectionalLight(0xffd5b0, 0.9 * intensity);
      fill.position.set(-2.5, 1.0, 2.0);
      scene.add(fill);

      const rim = new THREE.DirectionalLight(0xff7a3a, 1.4 * intensity);
      rim.position.set(-1.8, -2.6, -1.6);
      scene.add(rim);

      const ambient = new THREE.AmbientLight(0xfff3e6, 0.35);
      scene.add(ambient);

      // Mouse parallax — global, so the sphere reacts when user moves anywhere.
      let mx = 0, my = 0, tmx = 0, tmy = 0;
      mouseListener = (e) => {
        const w = window.innerWidth, h = window.innerHeight;
        tmx = (e.clientX / w) * 2 - 1;
        tmy = (e.clientY / h) * 2 - 1;
      };
      window.addEventListener("mousemove", mouseListener, { passive: true });

      const t0 = performance.now();
      function tick() {
        if (disposed) return;
        const t = (performance.now() - t0) / 1000;
        // Smoothly chase mouse target
        mx += (tmx - mx) * 0.06;
        my += (tmy - my) * 0.06;

        if (animate) {
          sphere.rotation.y = t * 0.35 + mx * 0.45;
          sphere.rotation.x = Math.sin(t * 0.55) * 0.18 + my * 0.30;
          sphere.position.y = Math.sin(t * 1.1) * 0.10;
          sphere.position.x = Math.cos(t * 0.7) * 0.04;
        } else {
          sphere.rotation.y = mx * 0.45;
          sphere.rotation.x = my * 0.30;
        }
        renderer.render(scene, camera);
        raf = requestAnimationFrame(tick);
      }
      tick();

      // React to --accent changes from the Tweaks panel.
      observer = new MutationObserver(() => {
        if (mat) mat.color.set(readAccent());
      });
      observer.observe(document.documentElement, { attributes: true, attributeFilter: ["style"] });
    }

    // Wait for THREE to load (script tag appended once globally).
    if (window.THREE) {
      start();
    } else {
      const wait = setInterval(() => {
        if (window.THREE) { clearInterval(wait); start(); }
      }, 50);
      // Safety: stop polling on dispose
      var __wait = wait;
    }

    return () => {
      disposed = true;
      cancelAnimationFrame(raf);
      if (mouseListener) window.removeEventListener("mousemove", mouseListener);
      if (observer) observer.disconnect();
      if (geo) geo.dispose();
      if (mat) mat.dispose();
      if (renderer) {
        renderer.dispose();
        if (renderer.domElement && renderer.domElement.parentNode) {
          renderer.domElement.parentNode.removeChild(renderer.domElement);
        }
      }
    };
  }, [size, animate, intensity]);

  return <div ref={ref} style={{ width: size, height: size, ...style }} aria-hidden="true" />;
}

window.ThreeBlob = ThreeBlob;
