// pdx-ui.jsx — Pokédex UI atoms. Exposes to window.
const { useState: useS, useEffect: useE, useRef: useR, useMemo: useM, useCallback: useC } = React;

const prefersReduced = () => window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;

// ── Icons ─────────────────────────────────────────────────────────────────
const I = ({ d, c, sw = 1.8, s = 18, vb = "0 0 24 24" }) => (
  <svg viewBox={vb} width={s} height={s} fill={c ? "currentColor" : "none"}
       stroke={c ? "none" : "currentColor"} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round">{d}</svg>
);
const IcoSearch = (p) => <I {...p} d={<><circle cx="11" cy="11" r="7" /><path d="m20 20-3.2-3.2" /></>} />;
const IcoBook = (p) => <I {...p} d={<path d="M5 4.5h11a2 2 0 0 1 2 2V20H7a2 2 0 0 0-2 2zM5 4.5V22M9 9h6M9 13h4" />} />;
const IcoGrid = (p) => <I {...p} d={<><rect x="3.5" y="3.5" width="7" height="7" rx="1.5" /><rect x="13.5" y="3.5" width="7" height="7" rx="1.5" /><rect x="3.5" y="13.5" width="7" height="7" rx="1.5" /><rect x="13.5" y="13.5" width="7" height="7" rx="1.5" /></>} />;
const IcoUsers = (p) => <I {...p} d={<><circle cx="9" cy="8" r="3.2" /><path d="M3.5 19c.6-3 3-4.5 5.5-4.5S14 16 14.5 19" /><path d="M15.5 5.2a3.2 3.2 0 0 1 0 6M17 14.6c2 .5 3.6 2 4 4.4" /></>} />;
const IcoBolt = (p) => <I {...p} c d={<path d="M13 2 4.5 13.2H11l-1 8.8L19 10.8h-6.5z" />} />;
const IcoCheck = (p) => <I {...p} d={<path d="m4.5 12.5 5 5 10-11" />} sw={2.2} />;
const IcoWarn = (p) => <I {...p} d={<><path d="M12 3.5 22 20H2z" /><path d="M12 10v4.5M12 17.4v.1" /></>} />;
const IcoX = (p) => <I {...p} d={<path d="M6 6l12 12M18 6 6 18" />} />;
const IcoChevron = (p) => <I {...p} d={<path d="m9 5 7 7-7 7" />} />;
const IcoCog = (p) => <I {...p} d={<><circle cx="12" cy="12" r="3.4" /><path d="M12 2.5v2.5M12 19v2.5M21.5 12H19M5 12H2.5M18.7 5.3l-1.8 1.8M7.1 16.9l-1.8 1.8M18.7 18.7l-1.8-1.8M7.1 7.1 5.3 5.3" /></>} />;

// ── Type badge (solid, 18 tokens) ──────────────────────────────────────────
function TypeBadge({ type, sm }) {
  return <span className={"tb" + (sm ? " sm" : "")} style={{ "--tc": `var(--type-${type.toLowerCase()})` }}>{type}</span>;
}
function TypeBadges({ types, sm }) {
  return <span className="row gap1 wrap">{(types || []).map((t) => <TypeBadge key={t} type={t} sm={sm} />)}</span>;
}

// ── Role banner / badge / pill ──────────────────────────────────────────────
function RoleBanner({ archetype }) {
  const r = window.roleOf(archetype);
  return (
    <div className="role-banner" style={{ "--rc": r.color }}>
      <span className="rb-glyph">{r.glyph}</span>
      <span className="rb-label">{r.label}</span>
    </div>
  );
}
function RolePill({ archetype, role }) {
  const r = window.roleOf(archetype);
  return <span className="role-pill" style={{ "--rc": r.color }}><span className="rp-glyph">{r.glyph}</span>{role || r.short}</span>;
}

// ── Sprite + Pokéball spinner ───────────────────────────────────────────────
function Spinner() { return <div className="ph"><div className="pokeball" /></div>; }

// Sprite base: dev serves /if-fusions/* via Vite middleware; prod points at the R2 CDN.
const SPR_BASE = (window.IF_SPRITE_BASE || "");
function Sprite({ src, alt, kind, style }) {
  const [loaded, setLoaded] = useS(false);
  const [failed, setFailed] = useS(false);
  if (kind === "ace") return <div className="spr ace" style={style}><div className="ph"><span className="glyph-tile">★</span></div></div>;
  if (kind === "unfused") return <div className="spr unfused" style={style}><div className="ph"><span className="glyph-tile">—</span></div></div>;
  if (!src || failed) return <div className="spr" style={style}><div className="ph"><span className="glyph-tile dim">?</span></div></div>;
  const url = SPR_BASE && src.startsWith("/if-fusions/") ? SPR_BASE + src.slice("/if-fusions/".length) : src;
  return (
    <div className="spr" style={style}>
      {!loaded && <Spinner />}
      <img src={url} alt={alt || ""}
           loading="lazy" width={96} height={96} className={loaded ? "loaded" : ""}
           style={{ position: "absolute", width: "92%", height: "92%" }}
           onLoad={() => setLoaded(true)}
           onError={() => setFailed(true)} />
    </div>
  );
}

// ── Stat bars (roll up on reveal; honors reduced-motion) ────────────────────
function StatBlock({ stats, bst, animate }) {
  const [shown, setShown] = useS(!animate || prefersReduced());
  useE(() => { if (animate && !prefersReduced()) { const t = setTimeout(() => setShown(true), 60); return () => clearTimeout(t); } }, [animate]);
  const maxV = Math.max(...stats.map((s) => s.value));
  return (
    <div className="stats">
      {stats.map((s) => {
        const c = window.pdxStatColor(s.value);
        const pct = Math.max(3, Math.min(100, (s.value / 255) * 100));
        return (
          <div className={"stat" + (s.value === maxV ? " max" : "")} key={s.label} style={{ "--sc": c }}>
            <span className="stat-l">{s.label}</span>
            <div className="stat-track"><div className="stat-fill" style={{ width: shown ? pct + "%" : "0%" }} /></div>
            <span className="stat-v">{s.value}</span>
          </div>
        );
      })}
      {bst != null && (
        <div className="stat" style={{ marginTop: "calc(var(--u)*1)" }}>
          <span className="stat-l" style={{ color: "var(--ink-2)" }}>BST</span>
          <div className="stat-track" style={{ background: "transparent", border: 0 }} />
          <span className="stat-v" style={{ fontWeight: 800 }}>{bst}</span>
        </div>
      )}
    </div>
  );
}

function MoveList({ moves, sig }) {
  return <div className="moves">{moves.map((m) => <span key={m.id} className={"move" + (sig ? " sig" : "")}>{m.name}</span>)}</div>;
}
function Peek({ move }) {
  if (!move) return null;
  return <span className="peek"><span className="dot" />{move.name}</span>;
}

// ── Seen store hook ─────────────────────────────────────────────────────────
function useSeen() {
  const [seen, setSeen] = useS(() => window.loadSeen());
  const mark = useC((key) => setSeen((prev) => {
    if (prev.has(key)) return prev;
    const next = new Set(prev); next.add(key); window.saveSeen(next); return next;
  }), []);
  return [seen, mark];
}

Object.assign(window, {
  prefersReduced, IcoSearch, IcoBook, IcoGrid, IcoUsers, IcoBolt, IcoCheck, IcoWarn, IcoX, IcoChevron, IcoCog,
  TypeBadge, TypeBadges, RoleBanner, RolePill, Sprite, Spinner, StatBlock, MoveList, Peek, useSeen,
});
