// Trazia · Premium marketing site — main app

const { useEffect, useRef, useState, useMemo } = React;

/* ---------- Hooks ---------- */
function useReveal(threshold = 0.15) {
  useEffect(() => {
    const els = document.querySelectorAll(".reveal, .split-word");
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          e.target.classList.add("in");
          io.unobserve(e.target);
        }
      });
    }, { threshold });
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  }, []);
}

function useScrolled(threshold = 24) {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > threshold);
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, [threshold]);
  return scrolled;
}

function useCountUp(target, { duration = 1600, decimals = 0, start = false } = {}) {
  const [n, setN] = useState(0);
  useEffect(() => {
    if (!start) return;
    const t0 = performance.now();
    let raf;
    const tick = (now) => {
      const t = Math.min(1, (now - t0) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      setN(target * eased);
      if (t < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [target, duration, start]);
  return decimals ? n.toFixed(decimals) : Math.round(n).toLocaleString("es-MX");
}

/* ---------- Word splitter ---------- */
function SplitWords({ text = "", delay = 0, step = 60, className = "" }) {
  const words = String(text).split(/(\s+)/);
  let i = 0;
  return (
    <span className={className}>
      {words.map((w, idx) => {
        if (/^\s+$/.test(w)) return <span key={idx}>{w}</span>;
        const d = delay + i * step;
        i++;
        return (
          <span key={idx} className="split-word" style={{ "--w-delay": `${d}ms` }}>
            <span>{w}</span>
          </span>
        );
      })}
    </span>
  );
}

/* ---------- Icons ---------- */
const I = {
  arrow: (p={}) => <svg width="14" height="14" viewBox="0 0 14 14" fill="none" {...p}><path d="M3 7h8m0 0L7.5 3.5M11 7l-3.5 3.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  check: (p={}) => <svg width="14" height="14" viewBox="0 0 14 14" fill="none" {...p}><path d="M2.5 7.5l3 3 6-7" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  trace: (p={}) => <svg width="22" height="22" viewBox="0 0 22 22" fill="none" {...p}><circle cx="5" cy="5" r="2" fill="currentColor"/><circle cx="17" cy="11" r="2" fill="currentColor"/><circle cx="9" cy="17" r="2" fill="currentColor"/><path d="M5 5q5 0 6 6t6 0M9 17q-2-3 0-6" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" fill="none" strokeDasharray="2 3"/></svg>,
  shield: (p={}) => <svg width="22" height="22" viewBox="0 0 22 22" fill="none" {...p}><path d="M11 2l7 3v6c0 4-3 7-7 9-4-2-7-5-7-9V5l7-3z" stroke="currentColor" strokeWidth="1.5" fill="none"/><path d="M7.5 11l2.5 2.5L15 8.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  bolt: (p={}) => <svg width="22" height="22" viewBox="0 0 22 22" fill="none" {...p}><path d="M12 2L4 12h6l-1 8 8-10h-6l1-8z" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinejoin="round"/></svg>,
  qr: (p={}) => <svg width="56" height="56" viewBox="0 0 56 56" fill="none" {...p}>
    <rect x="6" y="6" width="14" height="14" rx="2" stroke="#fff" strokeWidth="2"/>
    <rect x="36" y="6" width="14" height="14" rx="2" stroke="#fff" strokeWidth="2"/>
    <rect x="6" y="36" width="14" height="14" rx="2" stroke="#fff" strokeWidth="2"/>
    <rect x="11" y="11" width="4" height="4" fill="#fff"/>
    <rect x="41" y="11" width="4" height="4" fill="#fff"/>
    <rect x="11" y="41" width="4" height="4" fill="#fff"/>
    <rect x="26" y="6" width="3" height="6" fill="#fff"/>
    <rect x="32" y="14" width="3" height="3" fill="#fff"/>
    <rect x="26" y="20" width="3" height="3" fill="#fff"/>
    <rect x="38" y="32" width="3" height="3" fill="#fff"/>
    <rect x="44" y="38" width="6" height="3" fill="#fff"/>
    <rect x="38" y="44" width="3" height="6" fill="#fff"/>
    <rect x="26" y="36" width="3" height="3" fill="#fff"/>
    <rect x="32" y="42" width="3" height="3" fill="#fff"/>
    <rect x="26" y="48" width="3" height="2" fill="#fff"/>
  </svg>,
  layers: (p={}) => <svg width="40" height="40" viewBox="0 0 40 40" fill="none" {...p}><path d="M20 4l16 8-16 8L4 12l16-8z" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round"/><path d="M4 20l16 8 16-8M4 28l16 8 16-8" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round" opacity="0.5"/></svg>,
  brain: (p={}) => <svg width="40" height="40" viewBox="0 0 40 40" fill="none" {...p}><path d="M14 8c-3 0-5 2-5 5 0 1-2 2-2 4s2 3 2 4-1 3 1 5 4 1 4 1m12-19c3 0 5 2 5 5 0 1 2 2 2 4s-2 3-2 4 1 3-1 5-4 1-4 1M20 8v24" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" fill="none"/></svg>,
  shieldLg: (p={}) => <svg width="40" height="40" viewBox="0 0 40 40" fill="none" {...p}><path d="M20 4l13 5v10c0 7-6 13-13 17-7-4-13-10-13-17V9l13-5z" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round" fill="none"/><path d="M14 20l4 4 8-8" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/></svg>,
  plug: (p={}) => <svg width="40" height="40" viewBox="0 0 40 40" fill="none" {...p}><path d="M14 4v8m12-8v8M10 12h20v6c0 4-4 8-10 8s-10-4-10-8v-6zm10 22v4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" fill="none"/></svg>,
};

/* ============================================================
   NAV
   ============================================================ */
function Nav() {
  const scrolled = useScrolled(24);
  return (
    <header className={`nav ${scrolled ? "scrolled" : ""}`}>
      <div className="nav-inner">
        <a href="#top" className="nav-logo" aria-label="Trazia · ir al inicio"
           onClick={(e) => { e.preventDefault(); window.scrollTo({ top: 0, behavior: 'smooth' }); }}>
          <img src="assets/logo/trazia_logo_horizontal.svg" alt="Trazia"/>
        </a>
        <nav className="nav-links">
          <a href="#plataforma">Plataforma</a>
          <a href="#como-funciona">Cómo funciona</a>
          <a href="#modulos">Módulos</a>
          <a href="#resultados">Resultados</a>
          <a href="#uses">Casos</a>
        </nav>
        <div className="nav-cta">
          {/* BUG-02 fix: link explícito a la plataforma. Va a la izquierda del
              CTA primario; abrir en la misma pestaña porque el destino es la
              consola de la propia marca. */}
          <a href="https://app.trazia.io/login" className="nav-signin">
            Iniciar sesión
          </a>
          <a href="#contacto" className="nav-pill" onClick={openDemoModal('demo')}>
            Solicitar demo <I.arrow className="arrow"/>
          </a>
        </div>
      </div>
    </header>
  );
}

/* ============================================================
   HERO with animated route
   ============================================================ */
function HeroRoute() {
  // Route path through the dossier map
  const path = "M40 260 Q 80 220 130 220 T 230 180 T 340 130 T 440 80";
  const pathRef = useRef(null);
  const [progress, setProgress] = useState(0);
  const [pathLen, setPathLen] = useState(500);

  useEffect(() => {
    if (pathRef.current) setPathLen(pathRef.current.getTotalLength());
  }, []);

  useEffect(() => {
    let t0 = null, raf;
    const tick = (now) => {
      if (!t0) t0 = now;
      const t = ((now - t0) / 4200) % 1;
      // ease in out
      const eased = t < 0.5 ? 2*t*t : 1 - Math.pow(-2*t + 2, 2) / 2;
      setProgress(eased);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  // Get vehicle position along path
  const vehiclePos = useMemo(() => {
    if (!pathRef.current) return { x: 40, y: 260 };
    const p = pathRef.current.getPointAtLength(pathLen * progress);
    return { x: p.x, y: p.y };
  }, [progress, pathLen]);

  const checkpoints = [
    { x: 40, y: 260, label: "Origen", thresh: 0.0 },
    { x: 130, y: 220, label: "CP-01", thresh: 0.18 },
    { x: 230, y: 180, label: "CP-02", thresh: 0.42 },
    { x: 340, y: 130, label: "CP-03", thresh: 0.68 },
    { x: 440, y: 80, label: "Taller", thresh: 0.99 },
  ];

  const dashOffset = pathLen - pathLen * progress;

  return (
    <div className="hero-map-wrap">
      <div className="hero-map-grid"/>
      <svg className="hero-route-svg" viewBox="0 0 480 320" preserveAspectRatio="none">
        <defs>
          <radialGradient id="ping" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor="rgba(0,194,184,0.4)"/>
            <stop offset="100%" stopColor="rgba(0,194,184,0)"/>
          </radialGradient>
        </defs>
        {/* dashed full route (intent) */}
        <path d={path} className="hero-route-path"/>
        {/* solid trail (verified) */}
        <path
          ref={pathRef}
          d={path}
          className="hero-route-trail"
          style={{
            strokeDasharray: pathLen,
            strokeDashoffset: dashOffset,
            transition: "none",
          }}
        />
        {/* checkpoints */}
        {checkpoints.map((cp, i) => {
          const reached = progress >= cp.thresh;
          return (
            <g key={i}>
              {reached && <circle cx={cp.x} cy={cp.y} r="14" fill="url(#ping)">
                <animate attributeName="r" values="6;18;6" dur="2.4s" repeatCount="indefinite"/>
                <animate attributeName="opacity" values="0.8;0;0.8" dur="2.4s" repeatCount="indefinite"/>
              </circle>}
              <circle cx={cp.x} cy={cp.y} r="5"
                className={reached ? "hero-checkpoint" : "hero-checkpoint-pending"}/>
              {(i === 0 || i === checkpoints.length - 1) && (
                <text x={cp.x} y={cp.y - 14}
                  fill={reached ? "var(--trazia-teal)" : "rgba(255,255,255,0.4)"}
                  fontSize="9" fontFamily="JetBrains Mono, monospace"
                  textAnchor="middle" letterSpacing="0.6">
                  {cp.label.toUpperCase()}
                </text>
              )}
            </g>
          );
        })}
        {/* vehicle pin */}
        <g transform={`translate(${vehiclePos.x}, ${vehiclePos.y})`}>
          <circle r="12" fill="rgba(0,194,184,0.16)">
            <animate attributeName="r" values="8;16;8" dur="1.6s" repeatCount="indefinite"/>
          </circle>
          <circle r="6" className="hero-vehicle-pin"/>
          <circle r="3" fill="var(--trazia-teal)"/>
        </g>
      </svg>
    </div>
  );
}

function Hero() {
  return (
    <section className="hero">
      <div className="container hero-grid">
        <div>
          {/* BUG-01 fix: render the H1 as plain text. SplitWords was
              occasionally leaving the second line hidden (IntersectionObserver
              timing on the gradient-clipped <span>). The hero copy MUST be
              visible on first paint — animation is a nice-to-have. */}
          <h1 className="hero-title display-xxl">
            Trazabilidad auditable,<br/>
            <span className="accent">para cada siniestro.</span>
          </h1>
          <p className="hero-lede reveal" style={{ "--reveal-delay": "900ms" }}>
            Trazia digitaliza la cadena de custodia de tus vehículos. Convierte el arrastre en evidencia operativa en tiempo real para que tus áreas de siniestros y antifraude tengan el control total de cada traslado.
          </p>
          <div className="hero-cta reveal" style={{ "--reveal-delay": "1100ms" }}>
            <a href="#contacto" onClick={openDemoModal('demo')} className="btn btn-primary">Solicitar demo ejecutiva <I.arrow className="arrow"/></a>
            <a href="#contacto" onClick={openDemoModal('brief')} className="btn btn-ghost">Ver brief técnico</a>
          </div>
          <div className="hero-meta reveal" style={{ "--reveal-delay": "1300ms" }}>
            <span className="hero-meta-item">SOC 2 Type II en curso</span>
            <span className="hero-meta-item">LFPDPPP compliant</span>
            <span className="hero-meta-item">99.5% uptime SLA</span>
          </div>
        </div>
        <div className="reveal" style={{ "--reveal-delay": "300ms" }}>
          <div className="hero-dossier">
            <div className="hero-dossier-hd">
              <div>
                <div className="hero-dossier-id">CLM-2026-00084 · QLT-MX</div>
              </div>
              <div className="hero-dossier-status"><span className="dot"/>CUSTODIA ACTIVA</div>
            </div>
            <HeroRoute/>
            <div className="hero-dossier-foot">
              <div>
                <div className="hero-dossier-stat-label">Checkpoints</div>
                <div className="hero-dossier-stat-value"><span className="accent">3</span>/4</div>
              </div>
              <div>
                <div className="hero-dossier-stat-label">Tiempo activo</div>
                <div className="hero-dossier-stat-value">01:42:18</div>
              </div>
              <div>
                <div className="hero-dossier-stat-label">Desviación</div>
                <div className="hero-dossier-stat-value">+2.4%</div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div className="scroll-cue">SCROLL</div>
    </section>
  );
}

/* ============================================================
   LOGO MARQUEE
   ============================================================ */
function Logos() {
  const carriers = ["Quálitas", "GNP", "Mapfre", "HDI", "GMX", "AON", "Inter", "Active Re", "Sura", "Porto Seguro"];
  return (
    <section className="logos">
      <div className="logos-inner">
        <div className="logos-track-wrap">
          <div className="logos-track">
            {[...carriers, ...carriers].map((c, i) => (
              <div key={i} className="logo-name">{c}</div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

/* ============================================================
   PILLARS
   ============================================================ */
function Pillars() {
  const pillars = [
    { n: "01", title: "Trazar", body: "Monitorea la ruta exacta del vehículo siniestrado, eliminando la dependencia de reportes manuales y llamadas de seguimiento a grúas.", icon: <I.trace/> },
    { n: "02", title: "Respaldar", body: "Registra cada custodia y señal de GPS como evidencia firmada y exportable para tus expedientes de siniestros.", icon: <I.shield/> },
    { n: "03", title: "Auditar", body: "Recibe alertas automáticas sobre anomalías en el proceso para frenar fugas de capital y fraudes en tiempo real.", icon: <I.bolt/> },
  ];
  return (
    <section className="section pillars" id="plataforma">
      <div className="container">
        <div className="pillars-head">
          <div className="reveal">
            <div className="eyebrow">01 · Fundamento</div>
            <h2 className="display-xl" style={{ marginTop: 18, maxWidth: 620 }}>
              El trayecto del vehículo convertido en evidencia operativa.
            </h2>
          </div>
          <p className="lede reveal" style={{ "--reveal-delay": "120ms", maxWidth: 460 }}>
            Tres operaciones centralizadas. Trazia toma la lectura del dispositivo en campo y la transforma en datos 100% auditables para proteger la operación de tu aseguradora.
          </p>
        </div>
        <div className="pillars-grid">
          {pillars.map((p, i) => (
            <div key={p.n} className="pillar reveal" style={{ "--reveal-delay": `${i * 100}ms` }}>
              <div className="pillar-bg-num">{p.n}</div>
              <div className="pillar-icon">{p.icon}</div>
              <h3>{p.title}</h3>
              <p>{p.body}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

window.Nav = Nav;
window.Hero = Hero;
window.Logos = Logos;
window.Pillars = Pillars;
window.useReveal = useReveal;
window.SplitWords = SplitWords;
window.I = I;
