/* ===============================================
   LOGO 3D — extruded NEMO cube, Three.js
   Fixed-position rotating cube acting as background.
   Each section has a different camera/cube orientation.
   =============================================== */

const { useEffect, useRef } = React;

function Logo3D({ enabled = true }) {
  const mountRef = useRef(null);
  const stateRef = useRef({
    scrollY: 0,
    targetScrollY: 0,
    sectionT: 0,        // smoothed section progress 0..N
    targetSectionT: 0,
  });

  useEffect(() => {
    if (!enabled) return;
    if (!mountRef.current) return;
    let cancelled = false;

    const init = async () => {
      // Load three.js once
      if (!window.THREE) {
        await new Promise((res, rej) => {
          const s = document.createElement("script");
          s.src = "https://unpkg.com/three@0.160.0/build/three.min.js";
          s.onload = res;
          s.onerror = rej;
          document.head.appendChild(s);
        });
      }
      if (cancelled) return;
      const THREE = window.THREE;
      const mount = mountRef.current;
      if (!mount) return;

      /* ---------- Scene ---------- */
      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(38, mount.clientWidth / mount.clientHeight, 0.1, 100);
      camera.position.set(0, 0, 18);

      const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
      renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
      renderer.setSize(mount.clientWidth, mount.clientHeight);
      renderer.setClearColor(0x000000, 0);
      mount.appendChild(renderer.domElement);

      /* ---------- Lights ---------- */
      const amb = new THREE.AmbientLight(0xffffff, 0.8);
      scene.add(amb);
      const key = new THREE.DirectionalLight(0xffffff, 1.2);
      key.position.set(4, 6, 6);
      scene.add(key);
      const rim = new THREE.DirectionalLight(0xa83a4b, 0.5); // burgundy rim
      rim.position.set(-6, 2, -3);
      scene.add(rim);
      const fill = new THREE.DirectionalLight(0xffffff, 0.5);
      fill.position.set(0, -5, 4);
      scene.add(fill);

      /* ---------- Cube faces: alternate VIDEO loop / NEMO HUB logo ---------- */
      // Video element (looped, muted, inline) → VideoTexture
      const video = document.createElement("video");
      video.src = window.__asset("assets/nemo-cube.mp4");
      video.loop = true;
      video.muted = true;
      video.playsInline = true;
      video.setAttribute("playsinline", "");
      video.setAttribute("webkit-playsinline", "");
      video.crossOrigin = "anonymous";
      video.preload = "auto";
      video.style.position = "absolute";
      video.style.width = "2px";
      video.style.height = "2px";
      video.style.opacity = "0";
      video.style.pointerEvents = "none";
      mount.appendChild(video);
      const tryPlay = () => video.play().catch(() => {});
      video.addEventListener("canplay", tryPlay);
      tryPlay();

      const videoTex = new THREE.VideoTexture(video);
      videoTex.colorSpace = THREE.SRGBColorSpace;
      videoTex.minFilter = THREE.LinearFilter;
      videoTex.magFilter = THREE.LinearFilter;
      // Cover-fit a portrait 720x1280 video onto a square face (crop top/bottom)
      const setVideoCover = () => {
        const vw = video.videoWidth || 720;
        const vh = video.videoHeight || 1280;
        const ar = vw / vh; // < 1 for portrait
        if (ar < 1) {
          videoTex.repeat.set(1, ar);
          videoTex.offset.set(0, (1 - ar) / 2);
        } else {
          videoTex.repeat.set(1 / ar, 1);
          videoTex.offset.set((1 - 1 / ar) / 2, 0);
        }
      };
      video.addEventListener("loadedmetadata", setVideoCover);
      setVideoCover();

      // Logo face — big NEMO HUB logo on cream/burgundy ground
      const logoImg = await new Promise((res) => {
        const img = new Image();
        img.crossOrigin = "anonymous";
        img.onload = () => res(img);
        img.onerror = () => res(null);
        img.src = window.__asset("assets/logo-nemo-white.png");
      });

      function makeLogoTexture() {
        const SZ = 1024;
        const c = document.createElement("canvas");
        c.width = SZ; c.height = SZ;
        const g = c.getContext("2d");
        // cream ground
        g.fillStyle = "#f3ece0";
        g.fillRect(0, 0, SZ, SZ);
        // subtle vignette
        const grad = g.createRadialGradient(SZ*0.5, SZ*0.42, 80, SZ/2, SZ/2, SZ*0.85);
        grad.addColorStop(0, "rgba(255,255,255,0.0)");
        grad.addColorStop(1, "rgba(122,35,53,0.10)");
        g.fillStyle = grad;
        g.fillRect(0, 0, SZ, SZ);
        // big burgundy logo, centered, no text
        if (logoImg) {
          const lw = SZ * 0.74;
          const lh = (logoImg.height / logoImg.width) * lw;
          const off = document.createElement("canvas");
          off.width = lw; off.height = lh;
          const og = off.getContext("2d");
          og.drawImage(logoImg, 0, 0, lw, lh);
          og.globalCompositeOperation = "source-in";
          og.fillStyle = "#7a2335";
          og.fillRect(0, 0, lw, lh);
          g.drawImage(off, (SZ - lw) / 2, (SZ - lh) / 2);
        }
        const tex = new THREE.CanvasTexture(c);
        tex.anisotropy = renderer.capabilities.getMaxAnisotropy();
        tex.colorSpace = THREE.SRGBColorSpace;
        return tex;
      }

      const logoTex = makeLogoTexture();

      // BoxGeometry material order: [+X, -X, +Y, -Y, +Z, -Z]
      // Horizontal band (+X, +Z, -X, -Z) alternates logo-video-logo-video.
      // Top (+Y) and bottom (-Y) = logo only.
      const faceKind = {
        0: "logo",   // +X  band
        4: "video",  // +Z  band
        1: "logo",   // -X  band
        5: "video",  // -Z  band
        2: "logo",   // +Y  top
        3: "logo",   // -Y  bottom
      };
      const materials = [0,1,2,3,4,5].map((i) => new THREE.MeshStandardMaterial({
        map: faceKind[i] === "video" ? videoTex : logoTex,
        roughness: 0.6,
        metalness: 0.08,
        toneMapped: false,
      }));

      const SIZE = 7.0;
      const geom = new THREE.BoxGeometry(SIZE, SIZE, SIZE, 1, 1, 1);
      // bevel via separate edges
      const cube = new THREE.Mesh(geom, materials);
      scene.add(cube);

      // Soft edges: add wireframe highlight
      const edges = new THREE.EdgesGeometry(geom);
      const edgeLine = new THREE.LineSegments(
        edges,
        new THREE.LineBasicMaterial({ color: 0xa83a4b, transparent: true, opacity: 0.4 })
      );
      cube.add(edgeLine);

      /* ---------- Resize ---------- */
      const onResize = () => {
        if (!mount) return;
        const w = mount.clientWidth, h = mount.clientHeight;
        renderer.setSize(w, h);
        camera.aspect = w / h;
        camera.updateProjectionMatrix();
      };
      window.addEventListener("resize", onResize);

      /* ---------- Scroll & section tracking ---------- */
      const getSectionProgress = () => {
        // Find section data-screen-label elements; compute fractional index
        const secs = Array.from(document.querySelectorAll("[data-screen-label]"));
        if (!secs.length) return 0;
        const vh = window.innerHeight;
        const focus = window.scrollY + vh * 0.4;
        let prog = 0;
        for (let i = 0; i < secs.length; i++) {
          const r = secs[i].getBoundingClientRect();
          const top = r.top + window.scrollY;
          const bot = top + r.height;
          if (focus >= top && focus < bot) {
            prog = i + (focus - top) / (bot - top);
            return prog;
          }
          if (focus < top) return Math.max(0, i - 1 + 0.999);
        }
        return secs.length - 1;
      };

      const onScroll = () => {
        stateRef.current.targetScrollY = window.scrollY;
        stateRef.current.targetSectionT = getSectionProgress();
      };
      onScroll();
      window.addEventListener("scroll", onScroll, { passive: true });

      /* ---------- Animate ---------- */
      let raf;
      const animate = () => {
        if (cancelled) return;
        const st = stateRef.current;
        st.scrollY += (st.targetScrollY - st.scrollY) * 0.08;
        st.sectionT += (st.targetSectionT - st.sectionT) * 0.06;

        const t = performance.now() * 0.001;
        // Continuous slow tumble
        const idleX = Math.sin(t * 0.18) * 0.18;
        const idleY = t * 0.10;
        const idleZ = Math.cos(t * 0.15) * 0.08;

        // Per-section "lock" rotations — each section snaps to a different face dominantly
        const faceRots = [
          [ 0.10,  0.20,  0.00],     // 01 hero
          [-0.30,  Math.PI * 0.55,  0.10], // 02 about
          [ 0.40,  Math.PI * 1.05, -0.10], // 03 services
          [-0.20,  Math.PI * 1.55,  0.20], // 04 cases
          [ 0.30,  Math.PI * 0.30, -0.15], // 05 team
          [-0.40,  Math.PI * 0.85,  0.10], // 06 territory
          [ 0.20,  Math.PI * 1.30, -0.20], // 07 clients
          [ 0.00,  Math.PI * 1.85,  0.00], // 08 contact
        ];

        const i = Math.floor(st.sectionT);
        const f = st.sectionT - i;
        const a = faceRots[Math.max(0, Math.min(faceRots.length - 1, i))];
        const b = faceRots[Math.max(0, Math.min(faceRots.length - 1, i + 1))];
        const lerp = (x, y, k) => x + (y - x) * k;
        const ease = (k) => k < 0.5 ? 2 * k * k : 1 - Math.pow(-2 * k + 2, 2) / 2;
        const ef = ease(f);

        cube.rotation.x = lerp(a[0], b[0], ef) + idleX;
        cube.rotation.y = lerp(a[1], b[1], ef) + idleY;
        cube.rotation.z = lerp(a[2], b[2], ef) + idleZ;

        // Camera position drifts subtly with section so cube feels parallax
        camera.position.x = Math.sin(st.sectionT * 0.7) * 0.6;
        camera.position.y = Math.cos(st.sectionT * 0.5) * 0.4;
        camera.lookAt(0, 0, 0);

        // Fade: fully visible at hero, drops to ~10% once you scroll past it.
        const vh = window.innerHeight || 1;
        const fade = Math.max(0, Math.min(1, st.scrollY / (vh * 0.7)));
        const targetOpacity = 1 - fade * 0.7; // 1.0 → 0.3 (30% residuo)
        mount.style.opacity = targetOpacity.toFixed(3);

        renderer.render(scene, camera);
        raf = requestAnimationFrame(animate);
      };
      raf = requestAnimationFrame(animate);

      // Cleanup
      return () => {
        cancelled = true;
        cancelAnimationFrame(raf);
        window.removeEventListener("resize", onResize);
        window.removeEventListener("scroll", onScroll);
        renderer.dispose();
        if (mount && renderer.domElement.parentNode === mount) {
          mount.removeChild(renderer.domElement);
        }
        materials.forEach(m => { m.dispose(); });
        videoTex.dispose();
        logoTex.dispose();
        try { video.pause(); video.removeAttribute("src"); video.load(); } catch (e) {}
        geom.dispose();
        edges.dispose();
      };
    };

    let cleanup;
    init().then((c) => { cleanup = c; });
    return () => { cancelled = true; cleanup && cleanup(); };
  }, [enabled]);

  if (!enabled) return null;
  return <div ref={mountRef} className="cube-stage" />;
}

window.Logo3D = Logo3D;
