/* =========================================================================
   Shared components & hooks
   ========================================================================= */
const { useState, useEffect, useRef, useCallback, useMemo } = React;

/* ---- tiny inline icons (geometric only) ---- */
const Icon = {
  sun: (p) =>
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" {...p}>
      <circle cx="12" cy="12" r="4.2" />
      <path d="M12 2.6v2.4M12 19v2.4M2.6 12H5M19 12h2.4M5.2 5.2l1.7 1.7M17.1 17.1l1.7 1.7M18.8 5.2l-1.7 1.7M6.9 17.1l-1.7 1.7" />
    </svg>,

  moon: (p) =>
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M20 14.5A8 8 0 1 1 9.6 4a6.3 6.3 0 0 0 10.4 10.5z" />
    </svg>,

  arrowDown: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 5v14M6 13l6 6 6-6" /></svg>,
  arrowLeft: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M19 12H5M11 6l-6 6 6 6" /></svg>,
  arrowRight: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M5 12h14M13 6l6 6-6 6" /></svg>,
  chevron: (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M6 9l6 6 6-6" /></svg>
};

/* ---- Emblem image ---- */
function Emblem({ className = "", size, halo = false, style, src = "assets/emblem.png", alt = "左锡宁 纹章 / emblem" }) {
  const img = <img className={"emblem " + className} src={src} alt={alt}
  style={{ width: size, height: size ? size : undefined, ...style }} draggable="false" />;
  if (!halo) return img;
  return <span className="emblem-halo">{img}</span>;
}

/* ---- Cosmos backdrop: nebula + tiered starfield + grain ---- */
function Cosmos({ motif = "calm" }) {
  const stars = useMemo(() => {
    const count = motif === "lush" ? 200 : 130;
    const arr = [];
    for (let i = 0; i < count; i++) {
      const tier = Math.random();
      const glint = tier > 0.965; // four-point bright stars
      const big = tier > 0.84;
      arr.push({
        left: Math.random() * 100,
        top: Math.random() * 100,
        s: glint ? 2.6 + Math.random() * 1.4 : big ? 1.7 + Math.random() * 1.1 : 0.8 + Math.random() * 1,
        dur: 3.5 + Math.random() * 7,
        del: -(Math.random() * 10),
        omin: glint ? 0.55 : big ? 0.3 : 0.1,
        omax: glint ? 1 : big ? 0.95 : 0.55,
        glint
      });
    }
    return arr;
  }, [motif]);
  return (
    <div className="cosmos" aria-hidden="true">
      <img className="cosmos__img" src="assets/nebula2.jpg" alt="" />
      <div className="cosmos__veil"></div>
      <div className="cosmos__tint"></div>
      <div className="stars">
        {stars.map((s, i) =>
        <i key={i} className={s.glint ? "g" : ""} style={{ left: s.left + "%", top: s.top + "%", width: s.s, height: s.s, "--dur": s.dur + "s", "--del": s.del + "s", "--omin": s.omin, "--omax": s.omax }} />
        )}
        <span className="meteor"></span>
        <span className="meteor meteor--2"></span>
      </div>
      <div className="grain"></div>
    </div>);

}

/* ---- Controls: language + theme ---- */
function LangToggle({ lang, onToggle, t }) {
  return (
    <button className="ctl" onClick={onToggle} aria-label="Switch language" title="中 / EN">
      <span style={{ color: "var(--ink)", fontWeight: 600 }}>{lang === "zh" ? "中" : "EN"}</span>
      <span style={{ opacity: .35 }}>/</span>
      <span>{lang === "zh" ? "EN" : "中"}</span>
    </button>);

}
function ThemeToggle({ theme, onToggle }) {
  return (
    <button className="ctl" onClick={onToggle} aria-label="Toggle theme"
    title={theme === "dark" ? "Light" : "Dark"}>
      {theme === "dark" ? <Icon.sun /> : <Icon.moon />}
    </button>);

}

/* ---- Reveal on scroll (scroll-driven, robust; content never stuck hidden) ---- */
function useReveal() {
  const ref = useRef(null);
  useEffect(() => {
    let raf = 0;
    const reveal = () => {
      raf = 0;
      const vh = window.innerHeight || 800;
      document.querySelectorAll(".rise:not(.in)").forEach((e) => {
        if (e.getBoundingClientRect().top < vh * 0.92) e.classList.add("in");
      });
    };
    const onScroll = () => {if (!raf) raf = requestAnimationFrame(reveal);};
    reveal();
    requestAnimationFrame(reveal);
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    const t = setTimeout(reveal, 350);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      clearTimeout(t);cancelAnimationFrame(raf);
    };
  }, []);
  return ref;
}

/* ---- Section header ---- */
function SectionHead({ idx, title, cjk, en }) {
  return (
    <header className="sec-head rise">
      {idx && <span className="sec-head__idx">{idx}</span>}
      <h2 className="sec-head__title">{cjk ? <span className="cjk">{title}</span> : title}</h2>
      {en && <span className="sec-head__en">{en}</span>}
    </header>);

}

Object.assign(window, { Icon, Emblem, Cosmos, LangToggle, ThemeToggle, useReveal, SectionHead });