/// file: public/assets/js/modules/webgl-hero.js

/**
 * Discover overlay: same meridian as hero — faceted obsidian tear-drop (Three.js).
 */

import { teardropMeridianRadius } from './home-diamond/build-crystal-geometry.js';

/** @type {import('three') | null} */
let THREE = null;

/**
 * @param {HTMLCanvasElement} canvas
 * @param {{ menu?: boolean }} [opts]
 */
function createCrystalScene(canvas, opts = {}) {
  if (!THREE) return () => {};

  const menu = Boolean(opts.menu);
  const renderer = new THREE.WebGLRenderer({
    canvas,
    antialias: true,
    alpha: true,
    powerPreference: 'high-performance',
  });
  renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
  renderer.setClearColor(0x000000, 0);
  renderer.toneMapping = THREE.ACESFilmicToneMapping;
  renderer.toneMappingExposure = menu ? 1.08 : 1.02;

  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(42, 1, 0.1, 100);
  camera.position.set(0.02, 0.02, 3.78);

  const pmrem = new THREE.PMREMGenerator(renderer);
  pmrem.compileEquirectangularShader();

  const envScene = new THREE.Scene();
  envScene.add(new THREE.AmbientLight(0x4466aa, 0.28));
  const d1 = new THREE.DirectionalLight(0xffffff, 2.0);
  d1.position.set(4, 6, 5);
  envScene.add(d1);
  const d2 = new THREE.DirectionalLight(0xaaccff, 0.95);
  d2.position.set(-5, 2, -4);
  envScene.add(d2);
  const d3 = new THREE.DirectionalLight(0xffccd0, 0.45);
  d3.position.set(0, -4, 6);
  envScene.add(d3);
  const rt = pmrem.fromScene(envScene, 0.04);
  scene.environment = rt.texture;
  pmrem.dispose();

  const keyLight = new THREE.DirectionalLight(0xffffff, menu ? 1.12 : 1.4);
  keyLight.position.set(2.75, 3.15, 4.85);
  scene.add(keyLight);
  const fillLight = new THREE.DirectionalLight(0x8e9aad, menu ? 0.22 : 0.2);
  fillLight.position.set(-4.2, 0.2, 3.5);
  scene.add(fillLight);
  /** @type {import('three').DirectionalLight | null} */
  let rimMenu = null;
  /** @type {import('three').DirectionalLight | null} */
  let underMenuLight = null;
  if (menu) {
    rimMenu = new THREE.DirectionalLight(0xd0dff5, 0.42);
    rimMenu.position.set(-0.8, 0.35, -5.2);
    scene.add(rimMenu);
    underMenuLight = new THREE.DirectionalLight(0x5a6575, 0.06);
    underMenuLight.position.set(0, -5.5, 2);
    scene.add(underMenuLight);
  }

  /* Lathe: u=0 bottom (t=1), u=1 top (t=0) — shared meridian */
  const profile = [];
  const segs = 48;
  const yLo = -0.505;
  const yHi = 0.505;
  for (let i = 0; i <= segs; i++) {
    const u = i / segs;
    const y = yLo + u * (yHi - yLo);
    const tFromTop = 1 - u;
    const r = teardropMeridianRadius(tFromTop);
    profile.push(new THREE.Vector2(Math.max(0.004, r), y));
  }
  const geo = new THREE.LatheGeometry(profile, 30);
  geo.computeVertexNormals();

  const mat = new THREE.MeshPhysicalMaterial({
    color: new THREE.Color(0x060708),
    metalness: 0,
    roughness: 0.32,
    transmission: 0.06,
    thickness: 0.34,
    ior: 1.52,
    transparent: true,
    envMapIntensity: menu ? 0.78 : 0.72,
    clearcoat: 0.2,
    clearcoatRoughness: 0.2,
    reflectivity: 0.42,
    flatShading: true,
    side: THREE.DoubleSide,
  });

  const mesh = new THREE.Mesh(geo, mat);
  mesh.rotation.set(0.042, 0.2, 0.008);
  scene.add(mesh);

  const edgeGeo = new THREE.EdgesGeometry(geo, THREE.MathUtils.degToRad(30));
  const mkRim = (hex, scale) => {
    const l = new THREE.LineSegments(
      edgeGeo,
      new THREE.LineBasicMaterial({
        color: hex,
        transparent: true,
        opacity: menu ? 0.12 : 0.14,
        blending: THREE.AdditiveBlending,
        depthWrite: false,
      })
    );
    l.scale.setScalar(scale);
    return l;
  };
  const rimR = mkRim(0xff6a7a, 1.005);
  const rimB = mkRim(0x6ab4ff, 0.997);
  mesh.add(rimR);
  mesh.add(rimB);

  let w = 1;
  let h = 1;
  let raf = 0;
  const clock = new THREE.Clock();

  const resize = () => {
    const rect = canvas.getBoundingClientRect();
    w = Math.max(1, Math.floor(rect.width));
    h = Math.max(1, Math.floor(rect.height));
    renderer.setSize(w, h, false);
    camera.aspect = w / h;
    camera.updateProjectionMatrix();
  };

  resize();

  const baseScale = menu ? 1.05 : 1.18;
  mesh.scale.setScalar(baseScale);

  let exitPulse = 0;
  const onHeroIntroExit = () => {
    exitPulse = 1;
  };
  window.addEventListener('saneksa:hero-intro-exit', onHeroIntroExit);

  const tick = () => {
    if (menu) {
      const el = document.getElementById('discover-overlay');
      if (!el?.classList.contains('is-open')) {
        raf = requestAnimationFrame(tick);
        return;
      }
    }

    const t = clock.getElapsedTime();
    const target = window.__saneksaHeroTarget;
    let nx = 0.5;
    let ny = 0.5;
    let active = false;
    if (target && typeof target.nx === 'number') {
      nx = target.nx;
      ny = target.ny;
      active = Boolean(target.active);
    }

    const aimX = (nx - 0.5) * 2.1;
    const aimY = (ny - 0.5) * -1.32;
    const idle = 0.001 + (active ? 0.0045 : 0.00065);
    const yawBoost = active ? (nx - 0.5) * 0.035 : (nx - 0.5) * 0.009;
    mesh.rotation.y += idle + yawBoost;
    const pitchTarget = 0.12 + aimY;
    const rollTarget = aimX * 0.45;
    mesh.rotation.x = THREE.MathUtils.lerp(mesh.rotation.x, pitchTarget, active ? 0.12 : 0.06);
    mesh.rotation.z = THREE.MathUtils.lerp(mesh.rotation.z, rollTarget, active ? 0.11 : 0.055);

    const breathe = 1 + Math.sin(t * 0.85) * 0.008;
    let scaleFactor = baseScale * breathe;
    if (exitPulse > 0.008) {
      scaleFactor *= 1 + exitPulse * 0.22;
      exitPulse *= 0.89;
    } else {
      exitPulse = 0;
    }
    mesh.scale.setScalar(scaleFactor);

    rimR.rotation.y = Math.sin(t * 0.35) * 0.0015;
    rimB.rotation.y = -Math.sin(t * 0.35) * 0.0015;

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

  const onWinResize = () => resize();
  window.addEventListener('resize', onWinResize);

  return () => {
    cancelAnimationFrame(raf);
    window.removeEventListener('resize', onWinResize);
    window.removeEventListener('saneksa:hero-intro-exit', onHeroIntroExit);
    scene.remove(keyLight);
    scene.remove(fillLight);
    if (rimMenu) scene.remove(rimMenu);
    if (underMenuLight) scene.remove(underMenuLight);
    edgeGeo.dispose();
    geo.dispose();
    mat.dispose();
    rimR.material.dispose();
    rimB.material.dispose();
    rt.dispose();
    renderer.dispose();
  };
}

/**
 * @param {HTMLCanvasElement} canvas
 * @param {{ menu?: boolean }} [opts]
 */
async function boot(canvas, opts = {}) {
  if (!canvas || !(canvas instanceof HTMLCanvasElement)) return;
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;

  try {
    THREE = await import(
      /* @vite-ignore */ 'https://unpkg.com/three@0.160.0/build/three.module.js'
    );
  } catch (e) {
    console.warn('[webgl-hero] Three.js failed to load', e);
    return;
  }

  if (opts.menu) {
    return createCrystalScene(canvas, opts);
  }
}

export function initMenuCrystal() {
  const canvas = document.getElementById('menu-crystal-canvas');
  if (!canvas || !(canvas instanceof HTMLCanvasElement)) return;
  void boot(canvas, { menu: true });
}
