/* components.jsx — shared primitives, icons, neutral mockups */
const { useState, useEffect, useRef, useCallback } = React;

/* ---------- Scroll reveal ---------- */
function Reveal({ children, delay = 0, as = "div", className = "", once = false, style, ...rest }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduce) { el.style.opacity = "1"; el.style.transform = "none"; return; }

    const cs = getComputedStyle(el);
    const vRx = parseFloat(cs.getPropertyValue("--rx"));
    const vRy = cs.getPropertyValue("--ry").trim();
    const RX = isNaN(vRx) ? 0 : vRx;
    const RY = vRy === "" ? 30 : parseFloat(vRy) || 0;
    const easeOut = (p) => 1 - Math.pow(1 - p, 3);

    let raf = 0, t1 = 0, t2 = 0, poll = 0, state = "";
    const clearAll = () => { if (raf) cancelAnimationFrame(raf); raf = 0; clearTimeout(t1); clearTimeout(t2); };
    const setHidden = () => { el.style.opacity = "0"; el.style.transform = "translate3d(" + RX + "px," + RY + "px,0)"; };
    const finalize = () => { if (raf) cancelAnimationFrame(raf); raf = 0; el.style.opacity = "1"; el.style.transform = "none"; if (poll) { clearInterval(poll); poll = 0; } };

    const animateIn = () => {
      if (state === "in") return;
      state = "in";
      clearAll();
      setHidden();
      let start = null;
      const run = (now) => {
        if (start == null) start = now;
        const p = Math.min((now - start) / 720, 1);
        const e = easeOut(p);
        el.style.opacity = String(e);
        el.style.transform = "translate3d(" + RX * (1 - e) + "px," + RY * (1 - e) + "px,0)";
        if (p < 1) raf = requestAnimationFrame(run); else finalize();
      };
      // stagger, then animate
      t1 = setTimeout(() => { raf = requestAnimationFrame(run); }, delay);
      // SAFETY: timers fire even when rAF/animations are throttled/frozen —
      // guarantees the element reaches its visible end-state regardless.
      t2 = setTimeout(finalize, delay + 820);
    };

    const animateOut = (dir) => {
      if (once || state === "out") return;
      state = "out";
      clearAll();
      const oy = dir < 0 ? -14 : 14;
      const from = parseFloat(el.style.opacity || "1");
      const from0 = isNaN(from) ? 1 : from;
      let start = null;
      const run = (now) => {
        if (start == null) start = now;
        const p = Math.min((now - start) / 400, 1);
        const e = easeOut(p);
        el.style.opacity = String(from0 * (1 - e));
        el.style.transform = "translate3d(0," + oy * e + "px,0)";
        if (p < 1) raf = requestAnimationFrame(run); else el.style.opacity = "0";
      };
      raf = requestAnimationFrame(run);
      // a frozen exit harmlessly leaves the element visible — no forced hide
    };

    const evaluate = () => {
      const vh = window.innerHeight || 0;
      const r = el.getBoundingClientRect();
      const visible = r.top < vh * 0.9 && r.bottom > vh * 0.12;
      if (visible) animateIn();
      else if (state === "in") {
        if (r.bottom <= vh * 0.12) animateOut(-1);
        else if (r.top >= vh * 0.9) animateOut(1);
      }
    };

    const io = new IntersectionObserver(() => evaluate(), { threshold: [0, 0.12, 0.5, 0.9] });
    io.observe(el);
    // Call evaluate() directly (NOT wrapped in rAF, which is throttled when the
    // frame isn't painting) so scroll always re-evaluates.
    const onScroll = () => evaluate();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    const its = [setTimeout(evaluate, 60), setTimeout(evaluate, 300), setTimeout(evaluate, 700)];
    // low-frequency timer poll: guarantees state updates even if scroll/IO/rAF
    // are all throttled in a given environment. Stops once the element settles
    // visible (scroll + IO then handle any later exit/re-entry).
    poll = setInterval(evaluate, 400);
    // ultimate safety: never leave an on-screen element hidden
    const safe = setTimeout(() => {
      const r = el.getBoundingClientRect();
      if (state !== "in" && r.top < (window.innerHeight || 0) && r.bottom > 0) finalize();
    }, 2400);
    evaluate();

    return () => {
      io.disconnect();
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      if (raf) cancelAnimationFrame(raf);
      clearInterval(poll);
      clearTimeout(t1); clearTimeout(t2); clearTimeout(safe);
      its.forEach(clearTimeout);
    };
  }, [once, delay]);
  const Tag = as;
  return (
    <Tag ref={ref} className={"reveal " + className} style={{ ...style }} {...rest}>
      {children}
    </Tag>);

}

/* ---------- Spotlight card (pointer-following glow) ---------- */
function SpotlightCard({ children, style = {}, className = "" }) {
  return (
    <div className={"spot-card " + className} style={style}>
      <div className="spot-card__inner">{children}</div>
    </div>);

}

/* ---------- Buttons ---------- */
function ArrowIcon() {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
      <path d="M5 12h14M13 6l6 6-6 6" />
    </svg>);

}
function CTA({ children = "Quero desenvolver meu E‑Commerce", variant = "primary", big = false, small = false, onClick, withArrow = true }) {
  const sizeStyle = big ?
  { fontSize: "1.12rem", padding: "1.2em 2em" } :
  small ?
  { fontSize: ".94rem", padding: ".82em 1.45em", borderRadius: 13 } :
  undefined;
  return (
    <button className={"btn btn-" + variant} onClick={onClick} style={{ ...sizeStyle, whiteSpace: "nowrap" }}>
      <span>{children}</span>
      {withArrow && <ArrowIcon />}
    </button>);

}

/* ---------- Recurring inline CTA (used between sections) ---------- */
function jumpToContact() {
  document.getElementById("contato")?.scrollIntoView({ behavior: "smooth" });
}
function SectionCTA({ note, label = "Quero desenvolver meu E‑Commerce", dark = false, mt = 64 }) {
  return (
    <Reveal style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 16, marginTop: mt, textAlign: "center" }}>
      {note &&
      <p style={{
        fontFamily: "JetBrains Mono,monospace", fontSize: ".74rem", letterSpacing: ".18em", textTransform: "uppercase",
        color: dark ? "var(--text-dark-faint)" : "var(--text-light-faint)"
      }}>{note}</p>}
      <CTA onClick={jumpToContact} small>{label}</CTA>
    </Reveal>);

}

/* ---------- Section header ---------- */
function SectionHead({ eyebrow, title, sub, center = false, max = 720, eyebrowColor }) {
  return (
    <div style={{ textAlign: center ? "center" : "left", maxWidth: center ? max : "none", margin: center ? "0 auto" : 0 }}>
      {eyebrow &&
      <Reveal as="div" className="eyebrow accent" style={{ marginBottom: 18, display: "flex", gap: 12, alignItems: "center", justifyContent: center ? "center" : "flex-start", color: eyebrowColor }}>
          <span style={{ width: 26, height: 1, background: "currentColor", opacity: .55 }} />{eyebrow}{center && <span style={{ width: 26, height: 1, background: "currentColor", opacity: .55 }} />}
        </Reveal>}
      <Reveal as="h2" className="h2" delay={60}>{title}</Reveal>
      {sub && <Reveal as="p" className="lead text-dim" delay={120} style={{ marginTop: 20, maxWidth: 640, marginLeft: center ? "auto" : 0, marginRight: center ? "auto" : 0 }}>{sub}</Reveal>}
    </div>);

}

/* ---------- Animated counter ---------- */
function Counter({ to, prefix = "", suffix = "", dur = 1800 }) {
  const [val, setVal] = useState(0);
  const ref = useRef(null);
  const started = useRef(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !started.current) {
          started.current = true;
          const reduce = matchMedia("(prefers-reduced-motion:reduce)").matches;
          if (reduce) {setVal(to);return;}
          const t0 = performance.now();
          const tick = (t) => {
            const p = Math.min(1, (t - t0) / dur);
            const e2 = 1 - Math.pow(1 - p, 3);
            setVal(Math.round(to * e2));
            if (p < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.4 });
    io.observe(el);
    return () => io.disconnect();
  }, [to, dur]);
  return <span ref={ref} style={{ fontSize: "50px" }}>{prefix}{val.toLocaleString("pt-BR")}{suffix}</span>;
}

/* ---------- Infinite marquee ---------- */
function Marquee({ items, speed = 38 }) {
  // Repete o conjunto base o suficiente para uma "metade" exceder a largura da
  // tela; depois duplica para o loop -50% emendar sem vão/piscar.
  const half = [...items, ...items, ...items, ...items];
  const row = half.concat(half);
  return (
    <div className="marquee" style={{ overflow: "hidden", maskImage: "linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent)", WebkitMaskImage: "linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent)" }}>
      <div className="marquee__track" style={{ display: "flex", width: "max-content", animation: `marquee ${speed}s linear infinite` }}>
        {row.map((it, i) =>
        <div key={i} style={{ display: "flex", alignItems: "center", flex: "0 0 auto", marginRight: "clamp(40px,6vw,84px)", opacity: .6, transition: "opacity .3s" }}
        onMouseEnter={(e) => e.currentTarget.style.opacity = 1}
        onMouseLeave={(e) => e.currentTarget.style.opacity = .6}>
            <PlatformLogo logo={it} />
          </div>
        )}
      </div>
      <style>{`@keyframes marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}`}</style>
    </div>);

}

/* Platform logos — official brand marks (white), rendered as images */
function PlatformLogo({ logo }) {
  return (
    <img src={logo.src} alt={logo.name}
      style={{ height: logo.h || 32, width: "auto", display: "block", objectFit: "contain", userSelect: "none", pointerEvents: "none" }} />);

}

/* ---------- Neutral mockups (abstract, substituíveis) ---------- */
function bar(w, op = .14, h = 8, r = 4) {
  return { width: w, height: h, borderRadius: r, background: `rgba(255,252,252,${op})` };
}
function BrowserMockup({ title = "operacao.exemplo" }) {
  return (
    <div style={{ background: "var(--surface-dark)", border: "1px solid var(--border-dark-strong)", borderRadius: 16, overflow: "hidden", boxShadow: "var(--shadow-card)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "12px 16px", borderBottom: "1px solid var(--border-dark)" }}>
        <span style={{ width: 11, height: 11, borderRadius: 99, background: "#ff5f57" }} />
        <span style={{ width: 11, height: 11, borderRadius: 99, background: "#febc2e" }} />
        <span style={{ width: 11, height: 11, borderRadius: 99, background: "#28c840" }} />
        <span style={{ marginLeft: 14, flex: 1, height: 22, borderRadius: 8, background: "rgba(255,252,252,.06)", display: "flex", alignItems: "center", padding: "0 12px", fontFamily: "JetBrains Mono,monospace", fontSize: 11, color: "var(--text-dark-faint)" }}>{title}</span>
      </div>
      <div style={{ padding: 18, display: "grid", gridTemplateColumns: "1fr 2.2fr", gap: 16 }}>
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          <div style={bar("60%", .22, 10)} />
          <div style={bar("100%", .07, 60, 12)} />
          <div style={bar("100%", .07, 60, 12)} />
          <div style={bar("80%", .07, 34, 10)} />
        </div>
        <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
            <div style={bar("40%", .22, 12)} />
            <div style={{ ...bar("64px", 1, 26, 8), background: "var(--purple)" }} />
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12 }}>
            {[0, 1, 2].map((i) => <div key={i} style={{ aspectRatio: "1/.7", borderRadius: 12, background: i === 1 ? "rgba(170,0,238,.16)" : "rgba(255,252,252,.06)", border: "1px solid var(--border-dark)" }} />)}
          </div>
          <div style={bar("100%", .07, 80, 12)} />
        </div>
      </div>
    </div>);

}
function DashboardMockup() {
  const pts = [22, 34, 30, 46, 40, 58, 52, 70, 64, 82];
  const path = pts.map((p, i) => `${i / (pts.length - 1) * 100},${100 - p}`).join(" ");
  return (
    <div style={{ background: "var(--surface-dark-2)", border: "1px solid var(--border-dark-strong)", borderRadius: 16, padding: 18, boxShadow: "var(--shadow-card)" }}>
      <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 16 }}>
        <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
          <div style={bar("90px", .22, 11)} />
          <div style={{ fontFamily: "Rubik", fontWeight: 700, fontSize: 26, color: "var(--text-dark)" }}>+38<span style={{ fontSize: 15, color: "var(--purple-300)" }}>%</span></div>
        </div>
        <div style={{ display: "flex", gap: 6, alignItems: "flex-start" }}>
          {["7d", "30d", "12m"].map((t, i) => <span key={t} style={{ fontFamily: "JetBrains Mono", fontSize: 10, padding: "5px 9px", borderRadius: 7, background: i === 2 ? "var(--purple)" : "rgba(255,252,252,.06)", color: i === 2 ? "#fff" : "var(--text-dark-faint)" }}>{t}</span>)}
        </div>
      </div>
      <svg viewBox="0 0 100 100" preserveAspectRatio="none" style={{ width: "100%", height: 130 }}>
        <defs>
          <linearGradient id="g1" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="rgba(170,0,238,.45)" /><stop offset="100%" stopColor="rgba(170,0,238,0)" />
          </linearGradient>
        </defs>
        <polygon points={`0,100 ${path} 100,100`} fill="url(#g1)" />
        <polyline points={path} fill="none" stroke="#cf6bff" strokeWidth="1.6" vectorEffect="non-scaling-stroke" />
      </svg>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10, marginTop: 16 }}>
        {[["Pedidos", "1.2k"], ["Ticket", "R$ 312"], ["Conv.", "3.4%"]].map(([a, b]) =>
        <div key={a} style={{ background: "rgba(255,252,252,.04)", border: "1px solid var(--border-dark)", borderRadius: 10, padding: "10px 12px" }}>
            <div style={{ fontFamily: "JetBrains Mono", fontSize: 9.5, color: "var(--text-dark-faint)", letterSpacing: ".1em" }}>{a.toUpperCase()}</div>
            <div style={{ fontFamily: "Rubik", fontWeight: 600, fontSize: 16, marginTop: 4 }}>{b}</div>
          </div>
        )}
      </div>
    </div>);

}
function PhoneMockup() {
  return (
    <div style={{ width: 188, borderRadius: 30, padding: 9, background: "#0b080e", border: "1px solid var(--border-dark-strong)", boxShadow: "var(--shadow-card)" }}>
      <div style={{ borderRadius: 23, overflow: "hidden", background: "var(--surface-dark)", aspectRatio: "9/18.5", display: "flex", flexDirection: "column" }}>
        <div style={{ height: 60, background: "linear-gradient(135deg,rgba(170,0,238,.28),rgba(170,0,238,.05))", borderBottom: "1px solid var(--border-dark)", display: "flex", alignItems: "flex-end", padding: 12, gap: 8 }}>
          <div style={bar("36%", .35, 9)} /><div style={{ marginLeft: "auto", width: 22, height: 22, borderRadius: 7, background: "rgba(255,252,252,.12)" }} />
        </div>
        <div style={{ padding: 12, display: "flex", flexDirection: "column", gap: 10, flex: 1 }}>
          <div style={{ aspectRatio: "1/.62", borderRadius: 12, background: "rgba(170,0,238,.14)", border: "1px solid var(--border-dark)" }} />
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 9 }}>
            {[0, 1, 2, 3].map((i) => <div key={i} style={{ aspectRatio: "1/1.15", borderRadius: 10, background: "rgba(255,252,252,.05)", border: "1px solid var(--border-dark)" }} />)}
          </div>
          <div style={{ marginTop: "auto", height: 36, borderRadius: 10, background: "var(--purple)" }} />
        </div>
      </div>
    </div>);

}

Object.assign(window, {
  Reveal, CTA, SectionCTA, jumpToContact, ArrowIcon, SectionHead, Counter, Marquee, PlatformLogo,
  BrowserMockup, DashboardMockup, PhoneMockup, SpotlightCard
});