/* Clara v2 — Dynamic Guide dot
   Drives a single pink dot through the page in scroll-coupled scenes:
   1. Right-edge sway (default)
   2. Big explosion at "Aparece Clara" (Act 03)
   3. Snaps between step 1/2/3 in "Tres movimientos" (Act 04)
   4. Orbits the Clara core in "Agentes" (Act 08)
   5. Rides the central spine in "Casos de uso" (Act 09)
   The dot disappears smoothly during transitions between scenes. */

const { useEffect: useEffectV2g, useRef: useRefV2g, useState: useStateV2g } = React;

/* ----- helpers ----- */
function rect(sel) {
  const el = typeof sel === 'string' ? document.querySelector(sel) : sel;
  return el ? el.getBoundingClientRect() : null;
}
function lerpv2(a, b, t) { return a + (b - a) * Math.max(0, Math.min(1, t)); }
function easeOut(t) { return 1 - Math.pow(1 - t, 3); }
function easeInOut(t) { return t < 0.5 ? 2*t*t : 1 - Math.pow(-2*t + 2, 2) / 2; }

/* Spawn N particles from origin (x,y) outward in random directions */
function spawnParticles(origin, count = 14) {
  const layer = document.getElementById('v2-particle-layer');
  if (!layer) return;
  for (let i = 0; i < count; i++) {
    const el = document.createElement('div');
    el.className = 'v2-particle';
    const angle = (Math.PI * 2 * i) / count + (Math.random() - 0.5) * 0.4;
    const dist = 80 + Math.random() * 120;
    const dx = Math.cos(angle) * dist;
    const dy = Math.sin(angle) * dist;
    el.style.left = origin.x + 'px';
    el.style.top = origin.y + 'px';
    el.style.setProperty('--dx', dx + 'px');
    el.style.setProperty('--dy', dy + 'px');
    el.style.animationDelay = (Math.random() * 0.06) + 's';
    layer.appendChild(el);
    requestAnimationFrame(() => el.classList.add('fire'));
    setTimeout(() => el.remove(), 1500);
  }
}

const SECTION_LABELS = {
  '01 Hero':            '01 / 10 · pregunta',
  '02 Caos':            '02 / 10 · caos',
  '03 Aparece Clara':   '03 / 10 · clara',
  '04 Cómo funciona':   '04 / 10 · cómo funciona',
  '05 Asistente':       '05 / 10 · asistente',
  '06 Fuentes':         '06 / 10 · fuentes',
  '07 Dashboard':       '07 / 10 · dashboard',
  '08 Agentes':         '08 / 10 · agentes',
  '09 Casos de uso':    '09 / 10 · casos de uso',
  '10 Decisión':        '10 / 10 · decisión',
};

/* Compute the current section label by intersection with viewport center */
function findActiveSection() {
  const sections = document.querySelectorAll('section[data-screen-label]');
  const ymid = window.innerHeight * 0.45;
  let best = null;
  for (const s of sections) {
    const r = s.getBoundingClientRect();
    if (r.top <= ymid && r.bottom >= ymid) { best = s; break; }
  }
  if (!best && sections.length) {
    // fallback to nearest above
    let above = null;
    for (const s of sections) {
      const r = s.getBoundingClientRect();
      if (r.top <= ymid) above = s;
    }
    best = above || sections[0];
  }
  return best ? best.getAttribute('data-screen-label') : '';
}

/* Get progress (0..1) within a section */
function sectionProgress(sel) {
  const r = rect(sel);
  if (!r) return null;
  const vh = window.innerHeight;
  const total = r.height + vh;
  const t = (vh - r.top) / total;
  return Math.max(0, Math.min(1, t));
}

/* ----- main component ----- */
function GuideV2() {
  const dotRef = useRefV2g(null);
  const labelRef = useRefV2g(null);
  const explosionDoneRef = useRefV2g(false);
  const heroFinalFiredRef = useRefV2g(false);
  const lastSectionRef = useRefV2g('');

  // Mark body so v1 guide is hidden via CSS
  useEffectV2g(() => {
    document.body.classList.add('v2');
    return () => document.body.classList.remove('v2');
  }, []);

  useEffectV2g(() => {
    let raf = 0;

    const update = () => {
      raf = 0;
      const dot = dotRef.current;
      const label = labelRef.current;
      if (!dot || !label) return;

      const vw = window.innerWidth;
      const vh = window.innerHeight;
      const scrollY = window.scrollY;
      const docMax = (document.documentElement.scrollHeight - vh) || 1;
      const gp = Math.min(1, Math.max(0, scrollY / docMax));

      // ---- defaults: right-edge sway following scroll ----
      let x = vw - 38;
      let y = lerpv2(vh * 0.18, vh * 0.86, gp);
      // sway: only on dark sections (gp < 0.62)
      const swayAmp = gp < 0.62 ? 22 : 12;
      x += Math.sin(gp * Math.PI * 14) * swayAmp;
      let scale = 1;
      let opacity = 1;
      let dotColor = '#E8006F';

      // ---- scene: Hero Final — dot anchors to CLARA .live dot ----
      const heroSec0 = document.querySelector('section[data-screen-label="01 Hero"]');
      if (heroSec0 && heroFinalFiredRef.current) {
        const finalStage = heroSec0.querySelector('.final-stage');
        const liveEl = heroSec0.querySelector('.clara-logo .live');
        if (finalStage && liveEl) {
          const heroR = heroSec0.getBoundingClientRect();
          if (heroR.top < vh * 0.55 && heroR.bottom > vh * 0.45) {
            const lr = liveEl.getBoundingClientRect();
            x = lr.left + lr.width / 2;
            y = lr.top + lr.height / 2;
            scale = 1.4;
          }
        }
      }

      // active section
      const labelKey = findActiveSection();
      label.textContent = SECTION_LABELS[labelKey] || '';
      // Light/dark mode is decided by section, not by scroll progress —
      // sections 07–10 have explicit cream backgrounds.
      const lightZone = labelKey === '07 Dashboard'
                      || labelKey === '08 Agentes'
                      || labelKey === '09 Casos de uso'
                      || labelKey === '10 Decisión';
      label.style.color = lightZone ? '#1C1C1C' : '#F5F0E8';

      // ---- scene: Aparece Clara (Act 03) — center, explode ----
      const claraSec = document.querySelector('section[data-screen-label="03 Aparece Clara"]');
      if (claraSec) {
        const r = claraSec.getBoundingClientRect();
        if (r.top < vh * 0.6 && r.bottom > vh * 0.4) {
          // we're inside Act03 — pull toward center
          const localT = Math.max(0, Math.min(1, (vh * 0.6 - r.top) / (r.height * 0.5)));
          const titleEl = claraSec.querySelector('h2.typed');
          const tr = titleEl ? titleEl.getBoundingClientRect() : null;
          const targetX = tr ? tr.left + tr.width * 0.92 : vw / 2;
          const targetY = tr ? tr.top + tr.height * 0.5 : vh * 0.4;
          x = lerpv2(x, targetX, easeOut(localT));
          y = lerpv2(y, targetY, easeOut(localT));
          scale = 1 + localT * 1.4;
          // Fire explosion once around the title moment
          if (!explosionDoneRef.current && localT > 0.55) {
            explosionDoneRef.current = true;
            // explode
            dot.classList.add('halo-fire');
            spawnParticles({ x: targetX, y: targetY }, 18);
            // briefly hide dot, then return
            dot.style.opacity = '0';
            setTimeout(() => {
              dot.classList.remove('halo-fire');
              dot.style.opacity = '1';
            }, 600);
          }
        } else if (r.bottom < vh * 0.4) {
          // past — reset for re-entry possibility if user scrolls back up far
          // (we keep explosionDoneRef true so it doesn't refire repeatedly)
        }
      }

      // ---- scene: Tres Movimientos (Act 04) — hop ABOVE each step card ----
      const howSec = document.querySelector('section[data-screen-label="04 Cómo funciona"]');
      if (howSec) {
        const stepCards = howSec.querySelectorAll('.step');
        if (stepCards.length === 3) {
          // Detect that the cards row is in a "viewable" position — i.e. their
          // top is below the navbar (~80px) so we have room to float the dot
          // above them without it slipping behind the topnav.
          const firstCard = stepCards[0].getBoundingClientRect();
          const lastCard  = stepCards[2].getBoundingClientRect();
          const cardsTop = firstCard.top;
          const cardsBottom = firstCard.bottom;

          const inView = cardsBottom > 80 && cardsTop < vh * 0.7;

          if (inView) {
            // local progress: ramps as the cards row moves up through the
            // viewport. We start at 0 when cards top hits 60% of vh, finish at
            // 1 when cards top hits 10% of vh.
            const startY = vh * 0.60;
            const endY   = vh * 0.10;
            const localT = Math.max(0, Math.min(1, (startY - cardsTop) / (startY - endY)));

            const stepIdx = localT < 0.34 ? 0 : (localT < 0.67 ? 1 : 2);
            const stepT   = localT < 0.34 ? localT / 0.34
                          : localT < 0.67 ? (localT - 0.34) / 0.33
                                          : (localT - 0.67) / 0.33;

            // small parabolic hop as the dot enters each step
            const hop = Math.sin(Math.min(1, stepT * 2.5) * Math.PI) * 18;

            const cr = stepCards[stepIdx].getBoundingClientRect();
            const tx = cr.left + cr.width / 2;
            // Float ~40px above the card's top, but always leave at least
            // 110px of viewport room so the dot (scale 1.8, ~25px) stays clear
            // of the topnav even at the peak of its hop.
            const ty = Math.max(110, cr.top - 40);
            x = tx;
            y = ty - hop;
            scale = 1.8;

            stepCards.forEach((s, i) => s.classList.toggle('lit', i === stepIdx));
          } else {
            stepCards.forEach(s => s.classList.remove('lit'));
          }
        }
      }

      // ---- scene: Agentes (Act 08) — orbit the Clara core ----
      const agentsSec = document.querySelector('section[data-screen-label="08 Agentes"]');
      if (agentsSec) {
        const r = agentsSec.getBoundingClientRect();
        if (r.top < vh * 0.55 && r.bottom > vh * 0.35) {
          const core = agentsSec.querySelector('.agent-core');
          if (core) {
            const cr = core.getBoundingClientRect();
            const cx = cr.left + cr.width / 2;
            const cy = cr.top + cr.height / 2;
            const radius = cr.width * 0.95;
            const localT = Math.max(0, Math.min(1, (vh * 0.55 - r.top) / Math.max(1, r.height * 0.6)));
            const angle = localT * Math.PI * 2 - Math.PI / 2;
            x = cx + Math.cos(angle) * radius;
            y = cy + Math.sin(angle) * radius;
            scale = 1.1;
          }
        }
      }

      // ---- scene: Casos de uso (Act 09) — ride central spine ----
      const useSec = document.querySelector('section[data-screen-label="09 Casos de uso"]');
      if (useSec) {
        const r = useSec.getBoundingClientRect();
        const spine = useSec.querySelector('.spine-line');
        if (spine && r.top < vh * 0.9 && r.bottom > vh * 0.1) {
          const sr = spine.getBoundingClientRect();
          const spineX = sr.left + sr.width / 2;
          // y follows viewport-center clamped within spine
          const yt = Math.max(sr.top + 20, Math.min(sr.bottom - 20, vh * 0.55));
          // Smooth blend from prior x to spineX as we enter
          const enterT = Math.max(0, Math.min(1, (vh * 0.5 - r.top) / Math.max(1, r.height * 0.2)));
          x = lerpv2(x, spineX, easeInOut(enterT));
          y = yt;
          scale = 1.15;

          // drive spine fill
          const totalH = sr.height;
          const filled = Math.max(0, Math.min(totalH, yt - sr.top));
          const pct = (filled / totalH) * 100;
          const fill = spine.querySelector('.fill');
          if (fill) fill.style.setProperty('--h', pct.toFixed(2) + '%');

          // light up the rows whose vertical center is above the dot
          const rows = useSec.querySelectorAll('.spine-row');
          rows.forEach((row) => {
            const rr = row.getBoundingClientRect();
            const midY = rr.top + rr.height / 2;
            row.classList.toggle('lit', midY <= yt + 12);
          });
        }
      }

      // ---- scene: CTA (Act 10) — fade out the dot ----
      const ctaSec = document.querySelector('section[data-screen-label="10 Decisión"]');
      if (ctaSec) {
        const r = ctaSec.getBoundingClientRect();
        if (r.top < vh * 0.4) {
          const t = Math.max(0, Math.min(1, (vh * 0.4 - r.top) / (vh * 0.4)));
          opacity = 1 - t;
        }
      }

      // Save current section for transition detection (could be used for beats)
      lastSectionRef.current = labelKey;

      // Apply to DOM
      const size = 14 * scale;
      dot.style.width = size + 'px';
      dot.style.height = size + 'px';
      dot.style.left = x + 'px';
      dot.style.top = y + 'px';
      dot.style.opacity = String(opacity);

      // Label position (offset 28px left of dot)
      label.style.left = (x - 28) + 'px';
      label.style.top = y + 'px';
      label.style.transform = 'translate(-100%, -50%)';
      label.style.opacity = String(0.55 * opacity);
    };

    const onScroll = () => { if (!raf) raf = requestAnimationFrame(update); };

    update();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', update);
    return () => {
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', update);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);

  // Subscribe to beats — fire halo + particles at the dot's current position
  useEffectV2g(() => {
    const off = BeatBus.on((key) => {
      const dot = dotRef.current;
      if (!dot) return;

      if (key === 'beat-hero-final') {
        // Wait one tick for React to render .final-stage into the DOM
        setTimeout(() => {
          if (!dot) return;
          const liveEl = document.querySelector('.hero-banner .clara-logo .live');
          if (!liveEl) return;
          const lr = liveEl.getBoundingClientRect();
          const tx = lr.left + lr.width / 2;
          const ty = lr.top + lr.height / 2;
          // Teleport dot to the CLARA pink live-dot
          dot.style.left = tx + 'px';
          dot.style.top  = ty + 'px';
          dot.style.width  = '20px';
          dot.style.height = '20px';
          // Explode from CLARA
          dot.classList.remove('halo-fire');
          void dot.offsetWidth;
          dot.classList.add('halo-fire');
          spawnParticles({ x: tx, y: ty }, 22);
          dot.style.opacity = '0';
          setTimeout(() => {
            dot.classList.remove('halo-fire');
            dot.style.opacity = '1';
          }, 500);
          // Mark so the update loop keeps dot anchored at .live while hero is visible
          heroFinalFiredRef.current = true;
        }, 160);
        return;
      }

      // Default — fire halo at current position for all other beats
      const r = dot.getBoundingClientRect();
      dot.classList.remove('halo-fire');
      void dot.offsetWidth;
      dot.classList.add('halo-fire');
      spawnParticles({ x: r.left + r.width / 2, y: r.top + r.height / 2 }, 10);
    });
    return off;
  }, []);

  return (
    <React.Fragment>
      <div id="v2-particle-layer" className="v2-guide" aria-hidden="true" />
      <div className="v2-dot" ref={dotRef}>
        <div className="halo" />
      </div>
      <div className="v2-label" ref={labelRef} />
    </React.Fragment>
  );
}

/* Simplified TopNav v2 — switches by active section (Dashboard onward = light) */
function TopNavV2() {
  const [mode, setMode] = useStateV2g('mode-dark');
  useEffectV2g(() => {
    const onScroll = () => {
      const sections = document.querySelectorAll('section[data-screen-label]');
      const ymid = window.innerHeight * 0.25;
      let label = '';
      for (const s of sections) {
        const r = s.getBoundingClientRect();
        if (r.top <= ymid) label = s.getAttribute('data-screen-label') || '';
      }
      const light = ['07 Dashboard','08 Agentes','09 Casos de uso','10 Decisión'].includes(label);
      setMode(light ? 'mode-light' : 'mode-dark');
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    return () => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); };
  }, []);
  return (
    <header className={`topnav ${mode}`}>
      <div className="brand">
        <span className="glyph" />
        <span>reCLARA</span>
        <span className="clara-dot" />
      </div>
      <nav>
        <a href="#cmo">Producto</a>
        <a href="#use">Casos de uso</a>
        <a href="#cta">Precios</a>
      </nav>
      <a className="btn btn-primary cta-compact" href="#cta">Solicitar demo</a>
    </header>
  );
}

window.GuideV2 = GuideV2;
window.TopNavV2 = TopNavV2;

/* BackgroundFlow v2 — OKLCH interpolation + easing para transición orgánica */

// sRGB ↔ linear sRGB
function _bgLin(c) {
  const v = c / 255;
  return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
}
function _bgSrgb(c) {
  const g = c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
  return Math.max(0, Math.min(255, Math.round(g * 255)));
}

// HEX → [L, C, H] en OKLCH
function hexToOklch(hex) {
  const n = parseInt(hex.slice(1), 16);
  const r = _bgLin((n >> 16) & 255);
  const g = _bgLin((n >> 8) & 255);
  const b = _bgLin(n & 255);
  // Linear sRGB → LMS (Oklab M1)
  const l = 0.4122214708*r + 0.5363325363*g + 0.0514459929*b;
  const m = 0.2119034982*r + 0.6806995451*g + 0.1073969566*b;
  const s = 0.0883024619*r + 0.2817188376*g + 0.6299787005*b;
  const lc = Math.cbrt(l), mc = Math.cbrt(m), sc = Math.cbrt(s);
  // LMS → Oklab (M2)
  const L  =  0.2104542553*lc + 0.7936177850*mc - 0.0040720468*sc;
  const a  =  1.9779984951*lc - 2.4285922050*mc + 0.4505937099*sc;
  const bb =  0.0259040371*lc + 0.7827717662*mc - 0.8086757660*sc;
  const C  = Math.sqrt(a*a + bb*bb);
  const H  = (Math.atan2(bb, a) * 180 / Math.PI + 360) % 360;
  return [L, C, H];
}

// [L, C, H] → "rgb(r,g,b)"
function oklchToRgbStr(L, C, H) {
  const h = H * Math.PI / 180;
  const a = C * Math.cos(h), b = C * Math.sin(h);
  // Oklab → LMS (reverse M2)
  const lc = L + 0.3963377774*a + 0.2158037573*b;
  const mc = L - 0.1055613458*a - 0.0638541728*b;
  const sc = L - 0.0894841775*a - 1.2914855480*b;
  const l = lc*lc*lc, m = mc*mc*mc, s = sc*sc*sc;
  // LMS → linear sRGB (reverse M1)
  const r  =  4.0767416621*l - 3.3077115913*m + 0.2309699292*s;
  const g  = -1.2684380046*l + 2.6097574011*m - 0.3413193965*s;
  const bl = -0.0041960863*l - 0.7034186147*m + 1.7076147010*s;
  return `rgb(${_bgSrgb(r)},${_bgSrgb(g)},${_bgSrgb(bl)})`;
}

// Smootherstep — curva S ease-in-out sin derivadas abruptas en los extremos
function sstep(t) { return t*t*t*(t*(t*6-15)+10); }

// Misma paleta warm neutral de 10 paradas
const BG_STOPS_V2 = [
  '#0A0A0A', '#141414', '#1C1C1C', '#2A2622', '#4A423C',
  '#7A7570', '#B5A89B', '#D6CFC1', '#ECE5D7', '#F5F0E8'
];
// Posiciones ponderadas: el negro dura más (0–21%), el cream llega tarde (89–100%)
const BG_POS_V2 = [0, 0.07, 0.14, 0.21, 0.34, 0.50, 0.65, 0.78, 0.89, 1.0];
const BG_OKLCH_V2 = BG_STOPS_V2.map(hexToOklch);

function colorAtV2(p) {
  const pp = Math.max(0, Math.min(1, p));
  let s = 0;
  for (let i = BG_POS_V2.length - 2; i >= 0; i--) {
    if (pp >= BG_POS_V2[i]) { s = i; break; }
  }
  const t0 = BG_POS_V2[s], t1 = BG_POS_V2[s + 1];
  const t = (t1 > t0) ? sstep((pp - t0) / (t1 - t0)) : 0;
  const [La, Ca, Ha] = BG_OKLCH_V2[s];
  const [Lb, Cb, Hb] = BG_OKLCH_V2[s + 1];
  // Interpolación de hue por el camino más corto
  const dH = ((Hb - Ha + 540) % 360) - 180;
  return oklchToRgbStr(La+(Lb-La)*t, Ca+(Cb-Ca)*t, Ha+dH*t);
}

function BackgroundFlowV2() {
  const p = useScrollProgress();
  useEffectV2g(() => {
    const el = document.getElementById('bg-flow');
    if (el) el.style.backgroundColor = colorAtV2(p);
  }, [p]);
  return null;
}
window.BackgroundFlowV2 = BackgroundFlowV2;
