// Shared utilities for the CCSE 2026 website kit.
// Icon renders Lucide SVGs into a ref'd span (safe across React re-renders).
// Reveal is the scroll-reveal wrapper (IntersectionObserver + .rv CSS).

function Icon({ name, size = 20, strokeWidth = 2, style }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el || !window.lucide) return;
    const pas = name.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
    const def = lucide.icons ? lucide.icons[pas] || lucide.icons[name] : null;
    if (!def || !lucide.createElement) return;
    el.innerHTML = "";
    try {
      const svg = lucide.createElement(def);
      svg.setAttribute("width", size);
      svg.setAttribute("height", size);
      svg.setAttribute("stroke-width", strokeWidth);
      el.appendChild(svg);
    } catch (e) { /* icon lib mismatch — leave empty */ }
  }, [name, size, strokeWidth]);
  return <span ref={ref} aria-hidden="true" style={{ display: "inline-flex", width: size, height: size, flexShrink: 0, ...style }}></span>;
}

function Reveal({ children, delay = 0, style, className = "" }) {
  const ref = React.useRef(null);
  const [on, setOn] = React.useState(false);
  React.useEffect(() => {
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) { setOn(true); return; }
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setOn(true); io.disconnect(); }
    }, { threshold: 0.18, rootMargin: "0px 0px -40px 0px" });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return (
    <div ref={ref} className={className} style={{
      opacity: on ? 1 : 0,
      transform: on ? "none" : "translateY(var(--reveal-distance))",
      transition: `opacity var(--dur-reveal) var(--ease-out) ${delay}ms, transform var(--dur-reveal) var(--ease-out) ${delay}ms`,
      ...style,
    }}>{children}</div>
  );
}

// Live design-system accessor — resolves at call time (render), so the app
// self-heals if the bundle arrives after these scripts transpile.
function dsLib() { return window.CCSE2026DesignSystem_bedcf0 || {}; }

// ---- i18n plumbing ----
// Supported languages (order shown in the selector). Spanish is default.
const LANGS = [
  { code: "es", label: "Español", flag: "ES" },
  { code: "en", label: "English", flag: "EN" },
  { code: "ar", label: "العربية", flag: "AR" },
  { code: "ro", label: "Română", flag: "RO" },
  { code: "fr", label: "Français", flag: "FR" },
  { code: "ru", label: "Русский", flag: "RU" },
  { code: "zh", label: "中文", flag: "ZH" },
  { code: "de", label: "Deutsch", flag: "DE" },
  { code: "it", label: "Italiano", flag: "IT" },
];
const LANG_CODES = LANGS.map((l) => l.code);

// Resolve the initial language: ?lang= param → saved choice → browser → Spanish.
function detectLang() {
  try {
    const q = new URLSearchParams(location.search).get("lang");
    if (q && LANG_CODES.includes(q)) return q;
    const saved = localStorage.getItem("ccse-site-lang");
    if (saved && LANG_CODES.includes(saved)) return saved;
  } catch (e) {}
  const navs = (navigator.languages && navigator.languages.length ? navigator.languages : [navigator.language || ""]);
  for (const raw of navs) {
    const base = String(raw).toLowerCase().split("-")[0];
    if (LANG_CODES.includes(base)) return base;
  }
  return "es";
}

// {n}/{total} style interpolation.
function fmt(tpl, vars) {
  return String(tpl || "").replace(/\{(\w+)\}/g, (_, k) => (vars && k in vars ? vars[k] : "{" + k + "}"));
}

Object.assign(window, { Icon, Reveal, dsLib, LANGS, LANG_CODES, detectLang, fmt });
