// gallery.jsx — ideAs Productions 3D Gallery
// Screen in void — no room, only the glow

(function () {

  window.__ideAsGallery = {
    open: function (container, onClose) {
      const THREE = window.THREE;
      if (!THREE) { console.error('Three.js not loaded'); return; }

      // ── Overlay ──────────────────────────────────────────────────────────────
      const overlay = document.createElement('div');
      overlay.style.cssText = 'position:fixed;inset:0;z-index:200;background:#000;';
      container.appendChild(overlay);

      const canvas = document.createElement('canvas');
      canvas.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;display:block;';
      overlay.appendChild(canvas);

      const ui = document.createElement('div');
      ui.style.cssText = 'position:absolute;inset:0;pointer-events:none;';
      overlay.appendChild(ui);

      // Exit button
      const closeBtn = document.createElement('button');
      closeBtn.innerHTML = `<svg width="11" height="11" viewBox="0 0 11 11" fill="none">
        <line x1="1" y1="1" x2="10" y2="10" stroke="currentColor" stroke-width="1.2"/>
        <line x1="10" y1="1" x2="1" y2="10" stroke="currentColor" stroke-width="1.2"/>
      </svg>&nbsp;Exit`;
      closeBtn.style.cssText = `
        position:absolute; top:22px; right:24px; pointer-events:auto;
        background:none; border:1px solid rgba(255,255,255,0.12);
        color:rgba(255,255,255,0.3); padding:7px 14px; cursor:pointer;
        font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;
        font-size:10px; letter-spacing:0.16em; text-transform:uppercase;
        display:flex; align-items:center; gap:6px;
        transition:border-color 0.25s, color 0.25s;
      `;
      closeBtn.onmouseenter = () => {
        closeBtn.style.borderColor = 'rgba(255,255,255,0.45)';
        closeBtn.style.color = 'rgba(255,255,255,0.8)';
      };
      closeBtn.onmouseleave = () => {
        closeBtn.style.borderColor = 'rgba(255,255,255,0.12)';
        closeBtn.style.color = 'rgba(255,255,255,0.3)';
      };
      ui.appendChild(closeBtn);

      // ── Renderer ─────────────────────────────────────────────────────────────
      const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
      renderer.setSize(overlay.clientWidth, overlay.clientHeight);
      renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
      renderer.toneMapping = THREE.LinearToneMapping;
      renderer.toneMappingExposure = 1.0;

      const scene = new THREE.Scene();
      scene.background = new THREE.Color(0x000000);

      const camera = new THREE.PerspectiveCamera(62, overlay.clientWidth / overlay.clientHeight, 0.1, 60);
      const START_Z =  3.0;
      const END_Z   = -1.2;
      camera.position.set(0, 0, START_Z);

      // ── Video ────────────────────────────────────────────────────────────────
      const video = document.createElement('video');
      video.src = 'assets/works/003.mp4';
      video.crossOrigin = 'anonymous';
      video.loop = true;
      video.muted = true;
      video.playsInline = true;
      video.autoplay = true;
      video.style.display = 'none';
      document.body.appendChild(video);
      video.play().catch(() => {});

      const videoTex = new THREE.VideoTexture(video);
      videoTex.minFilter = THREE.LinearFilter;
      videoTex.magFilter = THREE.LinearFilter;

      // Screen dimensions — 572×1024 → 9:16
      const SW = 2.2, SH = (2.2 * 1024) / 572;
      const screenZ = -8;

      const screenMesh = new THREE.Mesh(
        new THREE.PlaneGeometry(SW, SH),
        new THREE.MeshBasicMaterial({ map: videoTex, toneMapped: false })
      );
      screenMesh.position.set(0, 0, screenZ);
      scene.add(screenMesh);

      // ── Halo sprites ─────────────────────────────────────────────────────────
      // Soft glow planes — additive blending, no geometry, pure light feel
      function makeHalo(size, opacity) {
        const c = document.createElement('canvas');
        c.width = 256; c.height = 256;
        const ctx = c.getContext('2d');
        const grad = ctx.createRadialGradient(128, 128, 0, 128, 128, 128);
        grad.addColorStop(0,   `rgba(255,255,255,${opacity})`);
        grad.addColorStop(0.4, `rgba(255,255,255,${opacity * 0.3})`);
        grad.addColorStop(1,   'rgba(0,0,0,0)');
        ctx.fillStyle = grad;
        ctx.fillRect(0, 0, 256, 256);
        const tex = new THREE.CanvasTexture(c);
        const mat = new THREE.MeshBasicMaterial({
          map: tex,
          transparent: true,
          blending: THREE.AdditiveBlending,
          depthWrite: false,
          toneMapped: false,
        });
        const mesh = new THREE.Mesh(new THREE.PlaneGeometry(size, size), mat);
        mesh.position.set(0, 0, screenZ + 0.05);
        scene.add(mesh);
        return { mesh, mat };
      }

      // Three layered halos — large soft outer, medium, small tight inner
      const haloOuter  = makeHalo(18, 0.06);
      const haloMid    = makeHalo(9,  0.10);
      const haloInner  = makeHalo(4,  0.18);

      // ── Luma sampler ─────────────────────────────────────────────────────────
      const sc = document.createElement('canvas');
      sc.width = 16; sc.height = 16;
      const sctx = sc.getContext('2d');

      function luma() {
        try {
          sctx.drawImage(video, 0, 0, 16, 16);
          const d = sctx.getImageData(0, 0, 16, 16).data;
          let s = 0;
          for (let i = 0; i < d.length; i += 4)
            s += d[i] * 0.299 + d[i+1] * 0.587 + d[i+2] * 0.114;
          return s / (16 * 16 * 255);
        } catch(e) { return 0.5; }
      }

      // ── Mouse look ───────────────────────────────────────────────────────────
      let tYaw = 0, tPitch = 0, cYaw = 0, cPitch = 0;
      overlay.addEventListener('mousemove', e => {
        tYaw   = -(e.clientX / overlay.clientWidth  - 0.5) * 0.5;
        tPitch =  (e.clientY / overlay.clientHeight - 0.5) * 0.28;
      });
      overlay.addEventListener('touchmove', e => {
        e.preventDefault();
        const t = e.touches[0];
        tYaw   = -(t.clientX / overlay.clientWidth  - 0.5) * 0.5;
        tPitch =  (t.clientY / overlay.clientHeight - 0.5) * 0.28;
      }, { passive: false });

      // ── Auto-approach ─────────────────────────────────────────────────────────
      let approachT = 0;
      const DURATION = 5.0;
      function easeOutQuart(t) { return 1 - Math.pow(1 - t, 4); }

      // ── Fade-in ───────────────────────────────────────────────────────────────
      overlay.style.opacity = '0';
      overlay.style.transition = 'opacity 1s ease';
      requestAnimationFrame(() => { overlay.style.opacity = '1'; });

      // ── Resize ────────────────────────────────────────────────────────────────
      const onResize = () => {
        renderer.setSize(overlay.clientWidth, overlay.clientHeight);
        camera.aspect = overlay.clientWidth / overlay.clientHeight;
        camera.updateProjectionMatrix();
      };
      window.addEventListener('resize', onResize);

      // ── Render loop ───────────────────────────────────────────────────────────
      const clock = new THREE.Clock();
      let rafId;

      function animate() {
        rafId = requestAnimationFrame(animate);
        const dt = Math.min(clock.getDelta(), 0.05);

        // Auto-approach
        if (approachT < 1) {
          approachT = Math.min(approachT + dt / DURATION, 1);
          camera.position.z = START_Z + (END_Z - START_Z) * easeOutQuart(approachT);
        }

        // Smooth look
        cYaw   += (tYaw   - cYaw)   * 0.055;
        cPitch += (tPitch - cPitch) * 0.055;
        camera.quaternion.setFromEuler(new THREE.Euler(cPitch, cYaw, 0, 'YXZ'));

        // Drive halo opacity from video luma
        const l = luma();
        const breathe = 0.85 + Math.sin(clock.elapsedTime * 0.8) * 0.15;
        haloOuter.mat.opacity = (0.5 + l * 0.5) * breathe;
        haloMid.mat.opacity   = (0.55 + l * 0.45) * breathe;
        haloInner.mat.opacity = (0.6  + l * 0.4)  * breathe;

        renderer.render(scene, camera);
      }
      animate();

      // ── Cleanup ───────────────────────────────────────────────────────────────
      function destroy() {
        cancelAnimationFrame(rafId);
        window.removeEventListener('resize', onResize);
        video.pause(); video.remove();
        renderer.dispose();
        overlay.style.opacity = '0';
        setTimeout(() => { overlay.remove(); if (onClose) onClose(); }, 400);
      }

      closeBtn.addEventListener('click', destroy);
      document.addEventListener('keydown', e => {
        if (e.code === 'Escape') destroy();
      }, { once: true });
    }
  };

})();
