/* ============================================================
   SHARED COMPONENTS
   ============================================================ */
const { useState, useEffect, useRef, useCallback } = React;

/* ---------- icons ---------- */
function ArrowDiag() {
  return (
    <svg viewBox="0 0 16 16" fill="none" width="100%" height="100%">
      <path d="M4 12L12 4M12 4H5M12 4V11" stroke="currentColor" strokeWidth="1.5" strokeLinecap="square"/>
    </svg>
  );
}
function ArrowRight({ s = 16 }) {
  return (
    <svg viewBox="0 0 24 16" fill="none" width={s} height={s * 0.66}>
      <path d="M0 8H22M22 8L15 1M22 8L15 15" stroke="currentColor" strokeWidth="1.5"/>
    </svg>
  );
}

/* sliding double-arrow link */
function ArrowLink({ children, onClick, href }) {
  const Tag = href ? "a" : "button";
  return (
    <Tag className="arrow-link" onClick={onClick} href={href}>
      <span>{children}</span>
      <span className="arw"><ArrowDiag/><ArrowDiag/></span>
    </Tag>
  );
}

/* ---------- placeholder media plate ---------- */
function Plate({ tint, label, corner, video, className = "", style = {}, onUnmute, muted }) {
  // parse lightness from the oklch tint to choose contrast
  const L = parseFloat((String(tint).match(/[\d.]+/) || [0.8])[0]);
  const dark = L < 0.6;
  return (
    <div className={"plate " + (dark ? "plate-dark " : "plate-light ") + className} style={{ "--tint": tint, ...style }}>
      {corner && <div className="plate-corner">{corner}</div>}
      {label && <div className="plate-label">{label}</div>}
      {video && (
        <button className="pill" onClick={(e) => { e.stopPropagation(); onUnmute && onUnmute(); }}>
          <span className="dot"></span>{muted ? "Unmute" : "Mute"}
        </button>
      )}
    </div>
  );
}

/* ---------- split-text reveal ---------- */
/* renders text as masked rows of words that slide up when .is-in is set on a parent */
function SplitWords({ text, className = "", el = "span" }) {
  const words = String(text).split(" ");
  const El = el;
  return (
    <El className={className}>
      {words.map((w, i) => (
        <span className="reveal-mask" key={i} style={{ marginRight: "0.28em" }}>
          <span className="reveal-word" style={{ animationDelay: (i * 0.05) + "s" }}>{w}</span>
        </span>
      ))}
    </El>
  );
}

/* ---------- intersection reveal wrapper ---------- */
/* NOTE: IntersectionObserver does not fire reliably in this preview
   iframe, so we use a scroll + rAF rect check instead. */
function Reveal({ children, className = "", as = "div", once = true, style = {} }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  const [shown, setShown] = useState(false); // fallback: force-visible if anim never plays
  useEffect(() => {
    const node = ref.current;
    if (!node) return;
    let done = false;
    let fallback = null;
    const check = () => {
      if (done) return;
      const r = node.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight;
      if (r.top < vh * 0.9 && r.bottom > 0) {
        setSeen(true);
        fallback = setTimeout(() => setShown(true), 1500);
        if (once) { done = true; cleanup(); }
      } else if (!once) {
        setSeen(false);
      }
    };
    const cleanup = () => {
      window.removeEventListener("scroll", check);
      window.removeEventListener("resize", check);
    };
    window.addEventListener("scroll", check, { passive: true });
    window.addEventListener("resize", check);
    const r1 = requestAnimationFrame(() => requestAnimationFrame(check));
    const t = setTimeout(check, 140);
    return () => { cleanup(); cancelAnimationFrame(r1); clearTimeout(t); if (fallback) clearTimeout(fallback); };
  }, [once]);
  const As = as;
  return (
    <As ref={ref} className={className + (seen ? " is-in" : "") + (shown ? " rv-shown" : "")} style={style}>
      {children}
    </As>
  );
}

/* ============================================================
   HEADER
   ============================================================ */
function Header({ route, go, openContact, blend }) {
  const onHome = route.page === "home";
  const nav = [
    { id: "home", label: "Index" },
    { id: "research", label: "Research" },
    { id: "lab", label: "Lab" },
    { id: "about", label: "About" },
  ];
  return (
    <header className={"site-header" + (blend ? " blend" : "")}>
      <button className="brand" onClick={() => go({ page: "home" })}>
        {onHome
          ? <span>Security, Research, <span className="serif">Architecture</span></span>
          : <span>Dylan <span className="serif">jeppesen</span></span>}
      </button>
      <nav className="nav">
        {nav.map((n, i) => (
          <React.Fragment key={n.id}>
            <a
              className={route.page === n.id || (n.id === "home" && route.page === "case") ? "active" : ""}
              onClick={(e) => {
                e.preventDefault();
                if (n.id === "research" || n.id === "lab") { go({ page: "home" }); }
                else go({ page: n.id });
              }}
              href="#"
            >{n.label}</a>
            {i < nav.length - 1 && <span className="sep">,</span>}
          </React.Fragment>
        ))}
      </nav>
      <button className="ul" onClick={openContact}>Send me a message</button>
    </header>
  );
}

Object.assign(window, { ArrowDiag, ArrowRight, ArrowLink, Plate, SplitWords, Reveal, Header });
