/// file: public/assets/js/modules/home-touch.js

/**
 * Home hero pointer layers: ripples, WebGL crystal target, glow, title tilt, grain, scan line.
 */
export function initHomeTouch() {
  const root = document.querySelector('[data-home-touch-root]');
  if (!root) return;

  const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  if (reduced) {
    window.__saneksaHeroTarget = { nx: 0.5, ny: 0.5, active: false };
    return;
  }

  const ripplesHost = document.getElementById('touch-ripples');
  const glow = root.querySelector('.hero__touch-glow');
  const orbs = root.querySelectorAll('.home-orb');
  const titleWrap = root.querySelector('.hero-resn__title-wrap');
  const grain = root.querySelector('.hero__grain');
  const scan = root.querySelector('.hero__touch-scan');
  const ring = root.querySelector('.hero__touch-ring');
  const manifesto = root.querySelector('.hero__manifesto-line');

  let nx = 0.5;
  let ny = 0.5;
  let prevNx = 0.5;
  let prevNy = 0.5;
  let inside = false;

  const smooth = (a, b, t) => a + (b - a) * t;

  const setHeroTarget = (x, y, active) => {
    const r = root.getBoundingClientRect();
    if (r.width < 1 || r.height < 1) return;
    nx = Math.max(0, Math.min(1, (x - r.left) / r.width));
    ny = Math.max(0, Math.min(1, (y - r.top) / r.height));
    window.__saneksaHeroTarget = { nx, ny, active };
  };

  const isInside = (clientX, clientY) => {
    const r = root.getBoundingClientRect();
    return clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom;
  };

  /* 1 — Ripples */
  const spawnRipple = (clientX, clientY) => {
    if (!ripplesHost || !isInside(clientX, clientY)) return;
    const el = document.createElement('span');
    el.className = 'touch-ripple';
    const rect = ripplesHost.getBoundingClientRect();
    el.style.left = `${clientX - rect.left}px`;
    el.style.top = `${clientY - rect.top}px`;
    ripplesHost.appendChild(el);
    setTimeout(() => el.remove(), 900);
  };

  const applyMotion = (clientX, clientY, active) => {
    if (!isInside(clientX, clientY)) return;
    inside = true;
    setHeroTarget(clientX, clientY, active);

    const speed = Math.hypot(nx - prevNx, ny - prevNy);
    prevNx = nx;
    prevNy = ny;

    /* 3 — Glow */
    if (glow) {
      glow.style.background = `radial-gradient(circle at ${nx * 100}% ${ny * 100}%, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.07) 30%, transparent 58%)`;
    }

    /* 4 — Orbs */
    orbs.forEach((orb, i) => {
      const d = (i + 1) * 0.42;
      const ox = (nx - 0.5) * 52 * d;
      const oy = (ny - 0.5) * 40 * d;
      orb.style.transform = `translate3d(${ox}px, ${oy}px, 0)`;
    });

    /* 5 — Title tilt */
    if (titleWrap) {
      const rx = (ny - 0.5) * -5.5;
      const ry = (nx - 0.5) * 7.5;
      titleWrap.style.transform = `perspective(1200px) rotateX(${rx}deg) rotateY(${ry}deg)`;
    }

    /* 6 — Grain */
    if (grain) {
      grain.style.opacity = String(0.045 + Math.min(0.12, speed * 14));
    }

    /* 7 — Scan + ring + manifesto */
    if (scan) {
      scan.style.top = `${ny * 100}%`;
      scan.style.opacity = '0.4';
    }
    if (ring) {
      const scale = 1 + Math.sin(performance.now() * 0.0022) * 0.025 + (nx - 0.5) * 0.035;
      ring.style.transform = `translate(-50%, -50%) scale(${scale})`;
    }
    if (manifesto) {
      manifesto.style.transform = `translateX(${(nx - 0.5) * 22}px)`;
    }
  };

  const resetSoft = () => {
    inside = false;
    prevNx = 0.5;
    prevNy = 0.5;
    window.__saneksaHeroTarget = { nx: 0.5, ny: 0.5, active: false };
    if (titleWrap) titleWrap.style.transform = '';
    if (scan) scan.style.opacity = '0';
    if (grain) grain.style.opacity = '';
    orbs.forEach((orb) => {
      orb.style.transform = '';
    });
    if (manifesto) manifesto.style.transform = '';
  };

  const onPointerMove = (e) => {
    if (!(e instanceof PointerEvent)) return;
    if (!isInside(e.clientX, e.clientY)) {
      if (inside) resetSoft();
      return;
    }
    applyMotion(e.clientX, e.clientY, true);
  };

  const onPointerDown = (e) => {
    if (!(e instanceof PointerEvent)) return;
    spawnRipple(e.clientX, e.clientY);
    /* Do not call applyMotion here: a tap applies tilt from click Y and reads as the whole block jumping. Motion follows pointermove only. */
  };

  window.addEventListener('pointermove', onPointerMove, { passive: true });
  window.addEventListener('pointerdown', onPointerDown, { passive: true });

  const r = root.getBoundingClientRect();
  setHeroTarget(r.left + r.width / 2, r.top + r.height / 2, false);
}
