// components.jsx — shared primitives: BlurText, FadeUp, Icons, CTAs, VideoCard, StickyCTA, Tweaks

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

// ---------- Icons (inline SVG, minimal) ----------
const Icon = {
  ArrowUpRight: ({ size = 16 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <line x1="7" y1="17" x2="17" y2="7"/><polyline points="7 7 17 7 17 17"/>
    </svg>
  ),
  Play: ({ size = 22 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
      <path d="M8 5v14l11-7z"/>
    </svg>
  ),
  ChevronDown: ({ size = 18 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
  ),
  Shield: ({ size = 22 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
  ),
  Lock: ({ size = 22 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg>
  ),
  Bolt: ({ size = 22 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><polyline points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
  ),
  MapPin: ({ size = 18 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg>
  ),
  Star: ({ size = 16 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor"><polygon points="12 2 15 8.5 22 9.3 17 14.2 18.2 21 12 17.8 5.8 21 7 14.2 2 9.3 9 8.5"/></svg>
  ),
  Scales: ({ size = 22 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3v18"/><path d="M5 7h14"/><path d="M3 13l3-6 3 6"/><path d="M15 13l3-6 3 6"/><path d="M3 13a3 3 0 006 0"/><path d="M15 13a3 3 0 006 0"/></svg>
  ),
  X: ({ size = 14 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor"><path d="M18 2h3.3l-7.2 8.3L23 22h-6.6l-5.1-6.8L5.3 22H2l7.8-8.9L1.5 2h6.8l4.6 6.2L18 2z"/></svg>
  ),
  Instagram: ({ size = 14 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6"><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="1" fill="currentColor"/></svg>
  ),
  TikTok: ({ size = 14 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor"><path d="M21 8.5a6.5 6.5 0 01-4.5-1.8v7.8a5.8 5.8 0 11-5.8-5.8c.3 0 .6 0 .9.1v3a2.8 2.8 0 102 2.7V2h3a4.8 4.8 0 004.4 4.5v2z"/></svg>
  ),
};

// ---------- BlurText ----------
function BlurText({ children, className = "", delay = 0, stagger = 90, as: As = "span" }) {
  const ref = useRef(null);
  const [inView, setInView] = useState(true);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const r = el.getBoundingClientRect();
    if (r.top < window.innerHeight && r.bottom > 0) { setInView(true); return; }
    setInView(false);
    const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setInView(true); io.disconnect(); } }, { threshold: 0.05 });
    io.observe(el); return () => io.disconnect();
  }, []);

  let wordIdx = 0;
  const renderString = (s, keyPrefix) => {
    const tokens = s.split(/(\s+)/);
    return tokens.map((tok, pi) => {
      if (tok === "") return null;
      if (/^\s+$/.test(tok)) return <React.Fragment key={`${keyPrefix}-s${pi}`}>{"\u00A0"}</React.Fragment>;
      const i = wordIdx++;
      const d = delay + i * stagger;
      return (
        <span key={`${keyPrefix}-w${pi}`} className={"blur-word " + (inView ? "in" : "")} style={{ transitionDelay: inView ? `${d}ms` : "0ms" }}>
          {tok}
        </span>
      );
    });
  };

  const arr = React.Children.toArray(children);
  const out = arr.map((c, ci) => {
    if (typeof c === "string") return <React.Fragment key={`c${ci}`}>{renderString(c, `c${ci}`)}</React.Fragment>;
    if (React.isValidElement(c) && c.type === "br") return <br key={`br${ci}`} />;
    if (React.isValidElement(c)) {
      const inner = typeof c.props.children === "string" ? renderString(c.props.children, `e${ci}`) : c.props.children;
      return React.cloneElement(c, { key: `e${ci}` }, inner);
    }
    return <React.Fragment key={`x${ci}`}>{c}</React.Fragment>;
  });

  return <As ref={ref} className={className}>{out}</As>;
}

// ---------- FadeUp ----------
function FadeUp({ children, delay = 0, className = "", as: As = "div", style = {} }) {
  const ref = useRef(null);
  const [inView, setInView] = useState(false);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const r = el.getBoundingClientRect();
    if (r.top < window.innerHeight && r.bottom > 0) { setInView(true); return; }
    const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setInView(true); io.disconnect(); } }, { threshold: 0.05 });
    io.observe(el); return () => io.disconnect();
  }, []);
  return (
    <As ref={ref} className={`fade-up ${inView ? "in" : ""} ${className}`} style={{ ...style, transitionDelay: inView ? `${delay}ms` : "0ms" }}>
      {children}
    </As>
  );
}

// ---------- CTA ----------
function CTA({ href, children, variant = "primary", onClick, className = "" }) {
  const cls = variant === "primary" ? "cta cta-primary liquid-glass-strong"
            : variant === "red" ? "cta-red-fill"
            : "cta-ghost";
  const Comp = href ? "a" : "button";
  return (
    <Comp className={`${cls} ${className}`} href={href} onClick={onClick} target={href && href.startsWith("http") ? "_blank" : undefined} rel={href && href.startsWith("http") ? "noopener" : undefined}>
      <span>{children}</span>
      {variant === "ghost"
        ? <span className="gh-arrow"><Icon.ArrowUpRight size={14} /></span>
        : <span className="arrow"><Icon.ArrowUpRight /></span>}
    </Comp>
  );
}

// ---------- Kicker ----------
function Kicker({ n, children }) {
  return <div className="kicker"><span className="sec">§</span>{n} — {children}</div>;
}

// ---------- VideoBg (hydration-safe background video) ----------
function VideoBg({ src, poster, style }) {
  // Smoke video replaced with lightweight CSS blob background (2026-04-23).
  // Signature preserved so existing call sites don't need changes.
  return (
    <div className="blob-bg" aria-hidden="true">
      <div className="blob-bg__blob blob-bg__blob--1" />
      <div className="blob-bg__blob blob-bg__blob--2" />
      <div className="blob-bg__blob blob-bg__blob--3" />
      <div className="blob-bg__blob blob-bg__blob--4" />
    </div>
  );
}

// ---------- VideoCard (PBAL clips) ----------
function VideoCard({ poster, mp4, hls, caption }) {
  const [playing, setPlaying] = useState(false);
  const vref = useRef(null);
  const play = () => {
    const v = vref.current; if (!v) return;
    if (!v.src && !v._hlsAttached) {
      if (window.Hls && window.Hls.isSupported() && hls) {
        try {
          const hlsjs = new window.Hls();
          hlsjs.loadSource(hls);
          hlsjs.attachMedia(v);
          v._hlsAttached = true;
        } catch (e) {
          v.src = mp4;
        }
      } else if (hls && v.canPlayType && v.canPlayType("application/vnd.apple.mpegurl")) {
        v.src = hls;
      } else {
        v.src = mp4;
      }
    }
    v.play().catch(() => {});
    setPlaying(true);
  };
  return (
    <div
      className={`pbal-card liquid-glass ${playing ? "playing" : ""}`}
      onClick={!playing ? play : undefined}
      data-mp4={mp4}
      data-hls={hls}
    >
      {!playing && <img className="pbal-poster" src={poster} alt="" loading="lazy" />}
      <video ref={vref} controls={playing} playsInline preload="none" poster={poster} />
      <div className="pbal-card-overlay" />
      {!playing && (
        <>
          <button className="pbal-play-btn" aria-label="Play video"><Icon.Play /></button>
          <div className="pbal-caption">{caption}</div>
        </>
      )}
    </div>
  );
}

// ---------- Sticky CTA ----------
function StickyCTA() {
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    const onScroll = () => setVisible(window.scrollY > window.innerHeight * 0.85);
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return (
    <a href="https://firebarlabs.com/collections/smell-proof-fashion" target="_blank" rel="noopener" className={`sticky-cta liquid-glass-strong ${visible ? "visible" : ""}`}>
      <span>Shop Smell-Proof Bags</span>
      <span className="arrow"><Icon.ArrowUpRight /></span>
    </a>
  );
}

// ---------- Tweaks panel ----------
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "heroImage": "mini_duffle",
  "accent": "pbal_red",
  "theme": "dark",
  "headlineVariant": "A"
}/*EDITMODE-END*/;

function TweaksPanel({ state, setState }) {
  const [editMode, setEditMode] = useState(false);
  useEffect(() => {
    const onMsg = (e) => {
      const d = e.data || {};
      if (d.type === "__activate_edit_mode") setEditMode(true);
      if (d.type === "__deactivate_edit_mode") setEditMode(false);
    };
    window.addEventListener("message", onMsg);
    window.parent.postMessage({ type: "__edit_mode_available" }, "*");
    return () => window.removeEventListener("message", onMsg);
  }, []);
  const update = (k, v) => {
    setState(s => ({ ...s, [k]: v }));
    window.parent.postMessage({ type: "__edit_mode_set_keys", edits: { [k]: v } }, "*");
  };
  if (!editMode) return null;
  const Opt = ({ k, v, label }) => (
    <button className={`tweaks-opt ${state[k] === v ? "active" : ""}`} onClick={() => update(k, v)}>{label}</button>
  );
  return (
    <div className="tweaks-panel liquid-glass-strong">
      <div className="tweaks-title">Tweaks</div>
      <div className="tweaks-row">
        <div className="tweaks-label">Hero photo</div>
        <div className="tweaks-opts">
          <Opt k="heroImage" v="mini_duffle" label="Mini Duffle" />
          <Opt k="heroImage" v="crossbody_exec" label="Exec Crossbody" />
          <Opt k="heroImage" v="backpack" label="Backpack" />
          <Opt k="heroImage" v="crossbody_essential" label="Essential" />
        </div>
      </div>
      <div className="tweaks-row">
        <div className="tweaks-label">Headline</div>
        <div className="tweaks-opts">
          <Opt k="headlineVariant" v="A" label="A — Search" />
          <Opt k="headlineVariant" v="B" label="B — #STFU" />
          <Opt k="headlineVariant" v="C" label="C — Premium" />
        </div>
      </div>
      <div className="tweaks-row">
        <div className="tweaks-label">Accent</div>
        <div className="tweaks-opts">
          <Opt k="accent" v="pbal_red" label="PBAL red" />
          <Opt k="accent" v="mono" label="Mono" />
          <Opt k="accent" v="greige" label="Greige" />
        </div>
      </div>
      <div className="tweaks-row">
        <div className="tweaks-label">Theme</div>
        <div className="tweaks-opts">
          <Opt k="theme" v="dark" label="Dark" />
          <Opt k="theme" v="light" label="Light" />
        </div>
      </div>
    </div>
  );
}


// Export to window
Object.assign(window, { Icon, BlurText, FadeUp, CTA, Kicker, VideoBg, VideoCard, StickyCTA, TweaksPanel, TWEAK_DEFAULTS });
