/* global React */
// KSM B2B Website — shared primitives
const { useState, useEffect, useRef } = React;

// ---- Icon (Lucide) -------------------------------------------------------
// Custom composite glyphs (not in Lucide) — drawn in Lucide's stroke style.
const CUSTOM_ICONS = {
  // Praying hands enclosed in the heraldic shield — for "Prayer and Spiritual Warfare"
  "shield-pray": '<path d="M19 5a1 1 0 0 1 1 1v6c0 4.6-3.2 7-7 8.4a1 1 0 0 1-.7 0C8.2 19 5 16.6 5 12V6a1 1 0 0 1 1-1c2 0 4.4-1.1 6-2.6a1.1 1.1 0 0 1 1.4 0C15 3.9 17 5 19 5Z"/><path d="M12 7.4C10.6 8.3 9.6 10.1 9.2 12c-.25 1.2-.3 2.7-.15 3.9.1.8.5 1.3 1.25 1.5"/><path d="M12 7.4c1.4.9 2.4 2.7 2.8 4.6.25 1.2.3 2.7.15 3.9-.1.8-.5 1.3-1.25 1.5"/><path d="M12 7.8v8.8"/><path d="M10.3 17.4Q12 18.1 13.7 17.4"/>'
};

function Icon({ name, size = 20, stroke = 1.75, color, style = {}, className = "" }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const custom = CUSTOM_ICONS[name];
    if (custom) {
      el.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="' + size + '" height="' + size +
        '" viewBox="0 0 24 24" fill="none" stroke="' + (color || "currentColor") + '" stroke-width="' + stroke +
        '" stroke-linecap="round" stroke-linejoin="round">' + custom + '</svg>';
      return;
    }
    if (window.lucide && window.lucide.icons) {
      const key = name.split("-").map(s => s[0].toUpperCase() + s.slice(1)).join("");
      const node = window.lucide.icons[key];
      if (node) {
        el.innerHTML = "";
        const svg = window.lucide.createElement(node);
        svg.setAttribute("width", size);
        svg.setAttribute("height", size);
        svg.setAttribute("stroke-width", stroke);
        if (color) svg.setAttribute("stroke", color);
        el.appendChild(svg);
      }
    }
  }, [name, size, stroke, color]);
  return <span ref={ref} className={className}
    style={{ display: "inline-flex", width: size, height: size, ...style }} />;
}

// ---- Eyebrow -------------------------------------------------------------
function Eyebrow({ children, tone = "navy", style = {} }) {
  const colors = { navy: "var(--navy-700)", gold: "var(--gold-600)", light: "var(--sky-300)", sky: "var(--sky-500)" };
  return (
    <div style={{
      fontFamily: "var(--font-label)", fontSize: 12.5, fontWeight: 600,
      letterSpacing: "0.18em", textTransform: "uppercase",
      color: colors[tone], ...style
    }}>{children}</div>
  );
}

// ---- Gold rule -----------------------------------------------------------
function GoldRule({ w = 48, style = {} }) {
  return <div style={{ width: w, height: 2, background: "var(--gold-500)", ...style }} />;
}

// ---- Pill / tag ----------------------------------------------------------
function Pill({ children, tone = "navy", style = {} }) {
  const tones = {
    navy: { bg: "var(--sky-100)", fg: "var(--navy-700)" },
    sky: { bg: "rgba(0,174,239,0.12)", fg: "var(--navy-700)" },
    gold: { bg: "rgba(201,162,75,0.16)", fg: "var(--gold-600)" },
    light: { bg: "rgba(255,255,255,0.12)", fg: "#fff" },
    dark: { bg: "var(--ink)", fg: "#fff" },
  };
  const t = tones[tone] || tones.navy;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 6,
      fontFamily: "var(--font-label)", fontSize: 11, fontWeight: 600,
      letterSpacing: ".1em", textTransform: "uppercase",
      background: t.bg, color: t.fg, padding: "6px 12px", borderRadius: 999, ...style
    }}>{children}</span>
  );
}

// ---- Button --------------------------------------------------------------
function Button({ children, variant = "primary", size = "md", icon, onClick, href, type, style = {} }) {
  const [hover, setHover] = useState(false);
  const [press, setPress] = useState(false);
  const pads = size === "lg" ? "16px 30px" : size === "sm" ? "10px 18px" : "13px 24px";
  const fs = size === "lg" ? 13.5 : size === "sm" ? 11.5 : 12.5;
  const base = {
    fontFamily: "var(--font-label)", fontWeight: 600, fontSize: fs,
    letterSpacing: "0.1em", textTransform: "uppercase", padding: pads,
    borderRadius: 6, border: "1.5px solid transparent", cursor: "pointer",
    display: "inline-flex", alignItems: "center", gap: 9, lineHeight: 1,
    transition: "all .2s var(--ease)", transform: press ? "scale(0.98)" : "none",
    textDecoration: "none", whiteSpace: "nowrap", ...style
  };
  const variants = {
    primary: hover
      ? { background: "linear-gradient(135deg, var(--gold-200) 0%, var(--gold-500) 46%, var(--gold-600) 100%)",
          color: "#1c1407", boxShadow: "0 6px 18px rgba(201,162,75,0.42), inset 0 1px 0 rgba(255,255,255,0.55)" }
      : { background: "var(--navy-700)", color: "#fff", boxShadow: "none" },
    accent: hover
      ? { background: "linear-gradient(135deg, var(--gold-200) 0%, var(--gold-500) 46%, var(--gold-600) 100%)",
          color: "#1c1407", boxShadow: "0 6px 18px rgba(201,162,75,0.42), inset 0 1px 0 rgba(255,255,255,0.55)" }
      : { background: "var(--sky-500)", color: "#04263f", boxShadow: "none" },
    gold: { background: hover ? "var(--gold-600)" : "var(--gold-500)", color: "#1c1407",
      boxShadow: hover ? "var(--shadow-md)" : "none" },
    enroll: hover
      ? { background: "linear-gradient(135deg, var(--gold-200) 0%, var(--gold-500) 46%, var(--gold-600) 100%)",
          color: "#1c1407", boxShadow: "0 6px 18px rgba(201,162,75,0.42), inset 0 1px 0 rgba(255,255,255,0.55)" }
      : { background: "var(--sky-500)", color: "#04263f", boxShadow: "none" },
    secondary: hover
      ? { background: "linear-gradient(135deg, var(--gold-200) 0%, var(--gold-500) 46%, var(--gold-600) 100%)",
          borderColor: "var(--gold-500)", color: "#1c1407",
          boxShadow: "0 6px 18px rgba(201,162,75,0.42), inset 0 1px 0 rgba(255,255,255,0.55)" }
      : { background: "transparent", borderColor: "var(--navy-700)", color: "var(--navy-700)" },
    "secondary-light": hover
      ? { background: "linear-gradient(135deg, var(--gold-200) 0%, var(--gold-500) 46%, var(--gold-600) 100%)",
          borderColor: "var(--gold-500)", color: "#1c1407",
          boxShadow: "0 6px 18px rgba(201,162,75,0.42), inset 0 1px 0 rgba(255,255,255,0.55)" }
      : { background: "transparent", borderColor: "rgba(255,255,255,0.55)", color: "#fff" },
    ghost: hover
      ? { background: "rgba(201,162,75,0.16)", color: "var(--gold-600)", borderColor: "transparent" }
      : { background: "transparent", color: "var(--navy-700)", borderColor: "transparent" },
  };
  const Tag = href ? "a" : "button";
  return (
    <Tag href={href} onClick={onClick} type={type}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => { setHover(false); setPress(false); }}
      onMouseDown={() => setPress(true)} onMouseUp={() => setPress(false)}
      style={{ ...base, ...variants[variant] }}>
      {children}
      {icon && <Icon name={icon} size={size === "sm" ? 15 : 17} stroke={2}
        style={variant === "ghost" ? { color: "var(--gold-600)" } : {}} />}
    </Tag>
  );
}

// ---- Section container ---------------------------------------------------
function Container({ children, narrow, style = {} }) {
  return <div style={{ width: "100%", maxWidth: narrow ? 820 : 1120, margin: "0 auto",
    padding: "0 32px", boxSizing: "border-box", ...style }}>{children}</div>;
}

// ---- Section heading block (eyebrow + title + optional lead) -------------
function SectionHead({ eyebrow, eyebrowTone = "navy", title, lead, align = "left", dark = false, maxLead = 620, style = {} }) {
  return (
    <div style={{ textAlign: align, maxWidth: align === "center" ? 760 : "none",
      margin: align === "center" ? "0 auto" : 0, ...style }}>
      {eyebrow && <Eyebrow tone={dark ? "light" : eyebrowTone} style={dark ? { color: "var(--gold-500)" } : {}}>{eyebrow}</Eyebrow>}
      <h2 style={{ fontFamily: "var(--font-display)", textTransform: "uppercase",
        fontSize: "clamp(1.9rem, 3.2vw, 2.9rem)", letterSpacing: ".015em", lineHeight: 1.07,
        color: dark ? "#fff" : "var(--ink)", margin: "14px 0 0" }}>{title}</h2>
      {align !== "center" && <GoldRule w={48} style={{ margin: "20px 0 0" }} />}
      {lead && <p style={{ fontFamily: "var(--font-sans)", fontSize: 18, lineHeight: 1.62,
        color: dark ? "rgba(255,255,255,0.8)" : "var(--slate)", margin: "22px auto 0",
        maxWidth: maxLead, marginLeft: align === "center" ? "auto" : 0, marginRight: align === "center" ? "auto" : 0,
        textWrap: "pretty" }}>{lead}</p>}
    </div>
  );
}

// reveal-on-scroll hook
function useReveal() {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  const [forced, setForced] = useState(false);  // hard fallback: snap visible (no transition)
  useEffect(() => {
    const el = ref.current; if (!el) { setShown(true); return; }
    let done = false;
    const reveal = () => { if (!done) { done = true; setShown(true); } };
    const io = new IntersectionObserver((entries, obs) => {
      if (entries[0].isIntersecting) { reveal(); obs.disconnect(); }
    }, { threshold: 0, rootMargin: "0px 0px -8% 0px" });
    io.observe(el);
    const t = setTimeout(reveal, 700);
    // Guarantee final visible state even where CSS transitions never advance
    // (print, PDF/PPTX capture, non-painting frames). Removing the transition
    // makes opacity:1 apply instantly instead of being stuck mid-tween.
    const f = setTimeout(() => setForced(true), 1500);
    return () => { io.disconnect(); clearTimeout(t); clearTimeout(f); };
  }, []);
  return [ref, shown, forced];
}

function Reveal({ children, delay = 0, style = {} }) {
  const [ref, shown, forced] = useReveal();
  const anim = forced
    ? { opacity: 1, transform: "none", transition: "none" }
    : { opacity: shown ? 1 : 0, transform: shown ? "none" : "translateY(16px)",
        transition: `opacity .6s var(--ease) ${delay}ms, transform .6s var(--ease) ${delay}ms` };
  return <div ref={ref} style={{ ...anim, ...style }}>{children}</div>;
}

// ---- Parallax (artistic, depth-layered scroll movement) ------------------
// Lightweight, registry-driven: one shared scroll/resize listener (rAF-throttled)
// drives every registered layer, so adding parallax anywhere costs ~nothing extra.
const _parallaxRegistry = [];
let _parallaxRAF = null;
const _prefersReducedMotion = () =>
  window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;

function _parallaxTick() {
  _parallaxRAF = null;
  const vh = window.innerHeight || 800;
  for (const item of _parallaxRegistry) {
    const el = item.ref.current;
    if (!el) continue;
    const rect = el.getBoundingClientRect();
    // progress: ~ -1 (entering bottom) .. 0 (centered) .. 1 (exiting top)
    const center = rect.top + rect.height / 2;
    const span = vh / 2 + rect.height / 2;
    const progress = span > 0 ? (vh / 2 - center) / span : 0;
    const shift = progress * item.speed;
    el.style.transform = (item.base ? item.base + " " : "") + "translate3d(0," + shift.toFixed(2) + "px,0)";
  }
}
function _scheduleParallax() {
  if (_parallaxRAF == null) _parallaxRAF = requestAnimationFrame(_parallaxTick);
}
let _parallaxBound = false;
function _ensureParallaxBound() {
  if (_parallaxBound) return;
  _parallaxBound = true;
  window.addEventListener("scroll", _scheduleParallax, { passive: true });
  window.addEventListener("resize", _scheduleParallax);
  _scheduleParallax();
}

// speed = max px of drift as the layer transits the viewport (try 14-50).
// baseTransform = a static transform to preserve (e.g. centering) alongside the drift.
function ParallaxLayer({ children, speed = 24, baseTransform = "", style = {}, className, ...rest }) {
  const ref = useRef(null);
  useEffect(() => {
    if (_prefersReducedMotion()) return;
    _ensureParallaxBound();
    const item = { ref, speed, base: baseTransform };
    _parallaxRegistry.push(item);
    _scheduleParallax();
    return () => {
      const i = _parallaxRegistry.indexOf(item);
      if (i >= 0) _parallaxRegistry.splice(i, 1);
    };
  }, [speed, baseTransform]);
  return <div ref={ref} className={className} style={{ willChange: "transform", transform: baseTransform || undefined, ...style }} {...rest}>{children}</div>;
}

// ---- Wordmark lockup (crest + Kingdom / School of Ministry) --------------
// One full-color logo; when `dark` (over a dark hero / transparent nav) it is
// whitened with a CSS filter, and shows its true navy/blue on a solid nav.
function Wordmark({ dark = false, crestHeight = 40, href = "index.html", onClick }) {
  const r = window.__resources || {};
  const crest = dark ? (r.crestWhite || "assets/logo-crest-white.png") : (r.crestNavy || "assets/logo-crest.png");
  const word = dark ? (r.wordWhite || "assets/logo-wordmark-white.png") : (r.wordNavy || "assets/logo-wordmark.png");
  return (
    <a href={href} onClick={onClick} style={{ display: "flex", alignItems: "center", gap: crestHeight * 0.26, textDecoration: "none" }}>
      <img src={crest} alt="Kingdom School of Ministry crest"
        style={{ height: crestHeight, width: "auto", display: "block", transition: "opacity .3s var(--ease)" }} />
      <img src={word} alt="Kingdom School of Ministry"
        style={{ height: crestHeight * 0.62, width: "auto", display: "block", transition: "opacity .3s var(--ease)" }} />
    </a>
  );
}

Object.assign(window, { Icon, Eyebrow, GoldRule, Pill, Button, Container, SectionHead, Reveal, useReveal, Wordmark, ParallaxLayer });
