/* =============================================================
   UPPAL — 3D Experience (Three.js)
   Floating architectural forms · gold highlights · depth fog
   Mouse rotation · scroll-controlled camera
   ============================================================= */
import * as THREE from "three";

const canvas = document.getElementById("three-canvas");
const prefersReduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

if (canvas && !prefersReduced) {
  initScene();
} else if (canvas) {
  // static fallback background
  canvas.style.background = "radial-gradient(60% 60% at 50% 40%, #141414, #050505)";
}

function initScene() {
  const scene = new THREE.Scene();
  const BG = new THREE.Color(0x050505);
  scene.background = BG;
  scene.fog = new THREE.FogExp2(0x050505, 0.05);

  const camera = new THREE.PerspectiveCamera(38, 1, 0.1, 100);
  camera.position.set(0, 0.6, 14);

  const renderer = new THREE.WebGLRenderer({
    canvas, antialias: true, alpha: false, powerPreference: "high-performance",
  });
  renderer.setClearColor(BG, 1);
  renderer.toneMapping = THREE.ACESFilmicToneMapping;
  renderer.toneMappingExposure = 1.05;

  const DPR = Math.min(window.devicePixelRatio || 1, 2);

  /* ---------- Lighting ---------- */
  const ambient = new THREE.AmbientLight(0x2a2a30, 1.1);
  scene.add(ambient);

  const key = new THREE.DirectionalLight(0xfff2d0, 2.2);
  key.position.set(6, 9, 8);
  scene.add(key);

  const goldRim = new THREE.PointLight(0xd4af37, 40, 60, 2);
  goldRim.position.set(-8, 3, 6);
  scene.add(goldRim);

  const coolFill = new THREE.PointLight(0x4a6a8a, 18, 60, 2);
  coolFill.position.set(9, -4, 4);
  scene.add(coolFill);

  const spot = new THREE.SpotLight(0xffe9b0, 30, 40, Math.PI / 6, 0.5, 1.2);
  spot.position.set(0, 12, 6);
  scene.add(spot);

  /* ---------- Materials ---------- */
  const towerMat = new THREE.MeshStandardMaterial({
    color: 0x101012, metalness: 0.85, roughness: 0.35,
    emissive: 0x000000,
  });
  const glassMat = new THREE.MeshPhysicalMaterial({
    color: 0x1a2230, metalness: 0.2, roughness: 0.05,
    transmission: 0.6, thickness: 1.2, transparent: true, opacity: 0.85,
    clearcoat: 1, clearcoatRoughness: 0.1, reflectivity: 0.9,
  });
  const goldMat = new THREE.MeshStandardMaterial({
    color: 0xd4af37, metalness: 1, roughness: 0.22,
    emissive: 0x3a2c08, emissiveIntensity: 0.4,
  });

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

  /* ---------- Central hero tower ---------- */
  const heroTower = new THREE.Group();
  const tiers = [
    { w: 2.4, h: 3.2, y: 0 },
    { w: 1.9, h: 2.6, y: 2.9 },
    { w: 1.4, h: 2.2, y: 5.3 },
    { w: 0.9, h: 1.6, y: 7.3 },
  ];
  tiers.forEach((t, i) => {
    const geo = new THREE.BoxGeometry(t.w, t.h, t.w);
    const mesh = new THREE.Mesh(geo, i % 2 === 0 ? towerMat : glassMat);
    mesh.position.y = t.y;
    heroTower.add(mesh);
    // gold band on top of each tier
    const band = new THREE.Mesh(
      new THREE.BoxGeometry(t.w + 0.06, 0.08, t.w + 0.06), goldMat
    );
    band.position.y = t.y + t.h / 2;
    heroTower.add(band);
  });
  // gold spire
  const spire = new THREE.Mesh(new THREE.CylinderGeometry(0.02, 0.14, 2.2, 12), goldMat);
  spire.position.y = 9.1;
  heroTower.add(spire);
  heroTower.position.y = -4.5;
  world.add(heroTower);

  /* ---------- Orbiting satellite structures ---------- */
  const satellites = [];
  const satGeoPool = [
    new THREE.BoxGeometry(1, 3.2, 1),
    new THREE.BoxGeometry(1.4, 2.2, 1.4),
    new THREE.CylinderGeometry(0.7, 0.7, 3, 6),
    new THREE.BoxGeometry(0.8, 4, 0.8),
    new THREE.IcosahedronGeometry(0.9, 0),
    new THREE.TorusGeometry(0.9, 0.14, 12, 40),
  ];
  for (let i = 0; i < 9; i++) {
    const geo = satGeoPool[i % satGeoPool.length];
    const isGold = i % 4 === 0;
    const isGlass = i % 3 === 0 && !isGold;
    const mat = isGold ? goldMat : isGlass ? glassMat : towerMat;
    const m = new THREE.Mesh(geo, mat);
    const angle = (i / 9) * Math.PI * 2;
    const radius = 6 + (i % 3) * 1.6;
    m.position.set(Math.cos(angle) * radius, (Math.random() - 0.5) * 6, Math.sin(angle) * radius - 2);
    m.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, 0);
    m.userData = {
      floatSpeed: 0.4 + Math.random() * 0.6,
      floatAmp: 0.4 + Math.random() * 0.5,
      baseY: m.position.y,
      spin: (Math.random() - 0.5) * 0.4,
      angle, radius,
    };
    satellites.push(m);
    world.add(m);
  }

  /* ---------- Gold particle field ---------- */
  const pCount = 380;
  const pGeo = new THREE.BufferGeometry();
  const pPos = new Float32Array(pCount * 3);
  for (let i = 0; i < pCount; i++) {
    pPos[i * 3] = (Math.random() - 0.5) * 40;
    pPos[i * 3 + 1] = (Math.random() - 0.5) * 26;
    pPos[i * 3 + 2] = (Math.random() - 0.5) * 30 - 4;
  }
  pGeo.setAttribute("position", new THREE.BufferAttribute(pPos, 3));
  const pMat = new THREE.PointsMaterial({
    color: 0xd4af37, size: 0.06, transparent: true, opacity: 0.55,
    depthWrite: false, blending: THREE.AdditiveBlending, sizeAttenuation: true,
  });
  const points = new THREE.Points(pGeo, pMat);
  scene.add(points);

  /* ---------- Ground reflection plane ---------- */
  const ground = new THREE.Mesh(
    new THREE.PlaneGeometry(80, 80),
    new THREE.MeshStandardMaterial({ color: 0x070707, metalness: 0.9, roughness: 0.4 })
  );
  ground.rotation.x = -Math.PI / 2;
  ground.position.y = -9;
  scene.add(ground);

  /* ---------- Interaction state ---------- */
  const pointer = { x: 0, y: 0, tx: 0, ty: 0 };
  let scrollProgress = 0;

  const section = document.querySelector(".experience");
  window.addEventListener("mousemove", (e) => {
    pointer.tx = (e.clientX / window.innerWidth - 0.5);
    pointer.ty = (e.clientY / window.innerHeight - 0.5);
  });
  window.addEventListener("deviceorientation", (e) => {
    if (e.gamma != null) { pointer.tx = Math.max(-0.5, Math.min(0.5, e.gamma / 60)); }
    if (e.beta != null) { pointer.ty = Math.max(-0.5, Math.min(0.5, (e.beta - 45) / 60)); }
  });

  function updateScroll() {
    if (!section) return;
    const rect = section.getBoundingClientRect();
    const vh = window.innerHeight;
    const total = rect.height - vh;
    scrollProgress = Math.max(0, Math.min(1, -rect.top / (total || 1)));
  }
  window.addEventListener("scroll", updateScroll, { passive: true });

  /* ---------- Resize ---------- */
  function resize() {
    const w = canvas.clientWidth || window.innerWidth;
    const h = canvas.clientHeight || window.innerHeight;
    renderer.setPixelRatio(DPR);
    renderer.setSize(w, h, false);
    camera.aspect = w / h;
    camera.updateProjectionMatrix();
  }
  window.addEventListener("resize", resize);

  /* ---------- Render loop (paused when off-screen) ---------- */
  const clock = new THREE.Clock();
  let visible = true;
  if (section) {
    const io = new IntersectionObserver(
      (entries) => entries.forEach((en) => { visible = en.isIntersecting; }),
      { threshold: 0.01 }
    );
    io.observe(section);
  }

  function animate() {
    requestAnimationFrame(animate);
    if (!visible) return;
    const t = clock.getElapsedTime();

    // smooth pointer
    pointer.x += (pointer.tx - pointer.x) * 0.05;
    pointer.y += (pointer.ty - pointer.y) * 0.05;

    // hero tower slow rotation + gentle bob
    heroTower.rotation.y = t * 0.12 + pointer.x * 0.6;
    heroTower.position.y = -4.5 + Math.sin(t * 0.5) * 0.15;

    // satellites float + orbit drift + spin
    satellites.forEach((m) => {
      const u = m.userData;
      m.position.y = u.baseY + Math.sin(t * u.floatSpeed + u.angle) * u.floatAmp;
      m.rotation.x += u.spin * 0.01;
      m.rotation.y += u.spin * 0.012;
      const a = u.angle + t * 0.04;
      m.position.x = Math.cos(a) * u.radius;
      m.position.z = Math.sin(a) * u.radius - 2;
    });

    // particle drift
    points.rotation.y = t * 0.02;
    points.position.y = Math.sin(t * 0.2) * 0.4;

    // world tilt from mouse (depth parallax)
    world.rotation.x = pointer.y * 0.25;
    world.rotation.y += ((pointer.x * 0.5) - world.rotation.y * 0 + 0) * 0; // base handled by hero

    // gold light orbit
    goldRim.position.x = Math.cos(t * 0.3) * 9;
    goldRim.position.z = Math.sin(t * 0.3) * 9 + 3;

    // scroll-controlled camera: dolly in + rise
    const targetZ = 14 - scrollProgress * 6.5;
    const targetY = 0.6 + scrollProgress * 3.2;
    camera.position.z += (targetZ - camera.position.z) * 0.06;
    camera.position.y += (targetY - camera.position.y) * 0.06;
    camera.position.x += ((pointer.x * 2.4) - camera.position.x) * 0.05;
    camera.lookAt(0, 0.5 + scrollProgress * 1.5, 0);

    renderer.render(scene, camera);
  }

  resize();
  updateScroll();
  animate();

  // reveal a subtle exposure fade-in
  renderer.toneMappingExposure = 0;
  const fadeStart = performance.now();
  (function expo() {
    const p = Math.min(1, (performance.now() - fadeStart) / 1400);
    renderer.toneMappingExposure = 1.05 * p;
    if (p < 1) requestAnimationFrame(expo);
  })();
}
