// pdx-fusions.jsx — Fusions Pokédex: role-first cards, filters, animated detail.
const { useState: useSF, useMemo: useMF, useEffect: useEF, useRef: useRF } = React;

// energy-cost pips from the fusion's typing
function EnergyPips({ types, sm }) {
  return <span className="energy">{types.map((t) => <span key={t} className={"pip" + (sm ? " sm" : "")} style={{ "--tc": `var(--type-${t.toLowerCase()})` }} />)}</span>;
}

// ── Fusion card = holographic Pokémon TCG card (moves on the face) ──────────
function FusionCard({ f, seen, onOpen, holo = true, idx = 0 }) {
  const r = window.roleOf(f.archetype);
  const ref = useRF(null);
  const t1 = `var(--type-${f.types[0].toLowerCase()})`;
  const t2 = f.types[1] ? `var(--type-${f.types[1].toLowerCase()})` : t1;
  const hp = (f.stats.find((s) => s.label === "HP") || {}).value;

  const onMove = (e) => {
    if (!holo || window.prefersReduced()) return;
    const el = ref.current; if (!el) return;
    const b = el.getBoundingClientRect();
    const px = (e.clientX - b.left) / b.width, py = (e.clientY - b.top) / b.height;
    el.style.setProperty("--ry", ((px - .5) * 18).toFixed(2) + "deg");
    el.style.setProperty("--rx", (-(py - .5) * 18).toFixed(2) + "deg");
    el.style.setProperty("--mx", (px * 100).toFixed(1) + "%");
    el.style.setProperty("--my", (py * 100).toFixed(1) + "%");
    el.style.setProperty("--gx", (px * 100).toFixed(1) + "%");
    el.style.setProperty("--gy", (py * 100).toFixed(1) + "%");
    el.style.transform = `rotateX(var(--rx)) rotateY(var(--ry)) scale(1.03)`;
    el.classList.add("tilting");
  };
  const onLeave = () => {
    const el = ref.current; if (!el) return;
    el.classList.remove("tilting");
    el.style.transform = ""; el.style.setProperty("--rx", "0deg"); el.style.setProperty("--ry", "0deg");
  };

  return (
    <button ref={ref} className={"tcg" + (seen ? " seen" : "") + (holo ? " holo-on" : "")}
      style={{ "--t1": t1, "--t2": t2, "--rc": r.color, "--scan-delay": (idx % 12 * 0.05).toFixed(2) + "s" }}
      onMouseMove={onMove} onMouseLeave={onLeave} onClick={() => onOpen(f)}>
      <span className="fc-scan" />
      <span className="tcg-foil" /><span className="tcg-glare" />
      <div className="tcg-inner">
        <div className="tcg-head">
          <div className="tcg-head-main">
            <div className="tcg-stage">{r.glyph} {r.short} · Fusion</div>
            <div className="tcg-name">{f.name}</div>
          </div>
          <div className="tcg-hp"><span className="hp-k">HP</span><span className="hp-v">{hp}</span><EnergyPips types={f.types} /></div>
        </div>

        <div className="tcg-art">
          <window.Sprite src={"/if-fusions/" + f.sprite} alt={f.name} />
          <span className="tcg-dex">№ {window.dexCode(f)}</span>
          <span className="tcg-seen" title="Registered" />
        </div>

        <div className="tcg-flavor"><b>{f.headName}</b> + <b>{f.bodyName}</b> — {f.signatureAxis}</div>

        <div className="tcg-panel">
          <div className="tcg-ability"><span className="ab-tag">Ability</span><span className="ab-name">{f.ability}</span></div>
          <div className="tcg-attacks">
            {f.signatureSet.map((m, i) => (
              <div className={"attack" + (i === 0 ? " sig" : "")} key={m.id}>
                <EnergyPips types={i === 0 ? f.types : [f.types[0]]} sm />
                <span className="atk-name">{m.name}</span>
                {i === 0 && <span className="atk-mark">★</span>}
              </div>
            ))}
          </div>
        </div>

        <div className="tcg-foot">
          <window.RolePill archetype={f.archetype} />
          <span className="tcg-bst"><span className="k">BST</span><span className="v">{f.bst}</span></span>
        </div>
      </div>
    </button>
  );
}

// ── Detail (role-first order: ROLE → moveset → ability/item → synergy → stats → learnset) ──
function Collapsible({ title, count, children }) {
  const [open, setOpen] = useSF(false);
  return (
    <div className={"collapse" + (open ? " open" : "")}>
      <button className="collapse-hd" onClick={() => setOpen((o) => !o)} aria-expanded={open}>
        <span className="chev"><window.IcoChevron s={13} /></span>{title}<span className="n">{count}</span>
      </button>
      {open && <div className="collapse-body"><window.MoveList moves={children} /></div>}
    </div>
  );
}

function LevelTable({ levelMoves }) {
  const half = Math.ceil(levelMoves.length / 2);
  const cols = [levelMoves.slice(0, half), levelMoves.slice(half)];
  return (
    <div className="lvl-grid">
      {cols.map((col, i) => (
        <table className="lvl-table" key={i}><tbody>
          {col.map((m) => (
            <tr key={m.id}><td className="lvl-num">{m.level === 1 ? "—" : m.level}</td><td className="lvl-move">{m.name}</td></tr>
          ))}
        </tbody></table>
      ))}
    </div>
  );
}

function FusionDetail({ fusion: f, siblings = [], onClose, onPick }) {
  const ref = useRF(null);
  const r = window.roleOf(f.archetype);
  const t1 = `var(--type-${f.types[0].toLowerCase()})`;
  const t2 = f.types[1] ? `var(--type-${f.types[1].toLowerCase()})` : t1;
  const idx = siblings.findIndex((s) => s.sprite === f.sprite);
  const prev = idx > 0 ? siblings[idx - 1] : null;
  const next = idx >= 0 && idx < siblings.length - 1 ? siblings[idx + 1] : null;

  useEF(() => {
    const onKey = (e) => {
      if (e.key === "Escape") onClose();
      else if (e.key === "ArrowRight" && next) onPick(next);
      else if (e.key === "ArrowLeft" && prev) onPick(prev);
    };
    document.addEventListener("keydown", onKey);
    const prevFocus = document.activeElement; ref.current?.focus(); document.body.style.overflow = "hidden";
    return () => { document.removeEventListener("keydown", onKey); document.body.style.overflow = ""; prevFocus?.focus?.(); };
  }, [onClose, onPick, next, prev]);

  return (
    <div className="fv-backdrop" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="fv" role="dialog" aria-modal="true" aria-label={f.name} ref={ref} tabIndex={-1}
           style={{ "--rc": r.color, "--t1": t1, "--t2": t2 }}>

        {/* LEFT — sprite hero */}
        <div className="fv-hero" key={f.sprite + "-hero"}>
          <span className="fv-hero-glow" />
          <span className="fv-sheen" />
          <button className="fv-close" onClick={onClose} aria-label="Close (Esc)"><window.IcoX s={18} /></button>
          {prev && <button className="fv-nav prev" onClick={() => onPick(prev)} aria-label="Previous fusion">‹</button>}
          {next && <button className="fv-nav next" onClick={() => onPick(next)} aria-label="Next fusion">›</button>}
          <div className="fv-sprite">
            <span className="fv-burst" />
            <window.Sprite src={"/if-fusions/" + f.sprite} alt={f.name} />
          </div>
          <div className="fv-id">
            <div className="fv-dex mono">№ {window.dexCode(f)}</div>
            <h2 className="fv-name">{f.name}</h2>
            <div className="fv-parents"><b>{f.headName}</b> + <b>{f.bodyName}</b></div>
            <div className="fv-types"><window.TypeBadges types={f.types} /></div>
          </div>
          {siblings.length > 1 && idx >= 0 && (
            <div className="fv-counter mono">{idx + 1} / {siblings.length}</div>
          )}
        </div>

        {/* RIGHT — dossier */}
        <div className="fv-dossier scrl" key={f.sprite + "-doss"}>
          <div className="d-role">
            <div className="d-section-k"><span className="n">01</span> Competitive role</div>
            <div className="d-role-banner">
              <span className="d-role-glyph">{r.glyph}</span>
              <div><div className="d-role-name">{r.label}</div><div className="d-role-axis">{f.signatureAxis}</div></div>
            </div>
          </div>

          <div className="d-block">
            <div className="d-section-k"><span className="n">02</span> Signature set</div>
            <window.MoveList moves={f.signatureSet} sig />
          </div>

          <div className="d-block">
            <div className="d-section-k"><span className="n">03</span> Ability &amp; item</div>
            <div className="kvs">
              <div className="kv"><span className="k">Ability</span><span className="v">{f.ability}</span></div>
              {f.hiddenAbility && <div className="kv"><span className="k">Hidden</span><span className="v hidden-abil">{f.hiddenAbility}</span></div>}
              {f.signatureItem && <div className="kv"><span className="k">Signature item</span><span className="v">{f.signatureItem}</span></div>}
              {f.orientation && <div className="kv"><span className="k">Lean</span><span className="v">{f.orientation[0] + f.orientation.slice(1).toLowerCase()}</span></div>}
            </div>
          </div>

          <div className="d-block">
            <div className="d-section-k"><span className="n">04</span> Base stats</div>
            <window.StatBlock stats={f.stats} bst={f.bst} animate />
          </div>

          <div className="d-block">
            <div className="d-section-k"><span className="n">05</span> Synergy check</div>
            {f.synergyOk
              ? <span className="synergy ok"><window.IcoCheck s={14} /> Clean — no anti-synergy flags</span>
              : <><span className="synergy warn"><window.IcoWarn s={14} /> {f.synergyFlags.length} warning{f.synergyFlags.length === 1 ? "" : "s"}</span>
                  <div className="synergy-flags">{f.synergyFlags.map((fl, i) => <div key={i}>{fl}</div>)}</div></>}
          </div>

          <div className="d-block">
            <div className="d-section-k"><span className="n">06</span> Level-up learnset <span className="n">{f.levelMoves.length}</span></div>
            <LevelTable levelMoves={f.levelMoves} />
            <Collapsible title="TM moves" count={f.tmMoves.length}>{f.tmMoves}</Collapsible>
            <div className="d-block">
              <div className="d-section-k">Curated movepool <span className="n">{f.movepool.length}</span></div>
              <window.MoveList moves={f.movepool} />
            </div>
          </div>

          <div className="credit">Sprite {f.spriteArtist ? <>by <b>{f.spriteArtist}</b></> : "— uncredited"} · served as <span className="mono">/if-fusions/{f.sprite}</span></div>
        </div>
      </div>
    </div>
  );
}

// ── Browser ─────────────────────────────────────────────────────────────────
function Dropdown({ value, onChange, options, placeholder }) {
  return <div className="sel"><select value={value} onChange={(e) => onChange(e.target.value)}>
    <option value="">{placeholder}</option>{options.map((o) => <option key={o} value={o}>{o}</option>)}
  </select></div>;
}

// ── Categorized landing (shown when no filter is engaged) ───────────────────
function Rail({ items, holo, seen, onOpen, caption }) {
  // infinite horizontal scroll — render a growing window as you scroll the rail right
  const [count, setCount] = useSF(14);
  useEF(() => { setCount(14); }, [items]);
  const onScroll = (e) => {
    const el = e.currentTarget;
    if (count < items.length && el.scrollLeft + el.clientWidth >= el.scrollWidth - 700) {
      setCount((c) => Math.min(items.length, c + 14));
    }
  };
  const shown = count >= items.length ? items : items.slice(0, count);
  return (
    <div className="rail scrl" onScroll={onScroll}>
      {shown.map((f, i) => (
        <div className="rail-item" style={{ "--i": Math.min(i, 14) }} key={f.sprite}>
          <FusionCard f={f} idx={i} holo={holo} seen={seen.has(window.fusionKey(f))} onOpen={onOpen} />
          {caption && <div className="rail-cap"><window.IcoBolt s={10} />{caption(f)}</div>}
        </div>
      ))}
    </div>
  );
}

function RailHead({ num, color, glyph, title, sub, onSeeAll }) {
  return (
    <div className={"rail-head" + (onSeeAll ? " clickable" : "")} style={{ "--rc": color || "var(--glow)" }} onClick={onSeeAll}>
      <span className="rail-num mono">{num}</span>
      {glyph && <span className="rail-glyph">{glyph}</span>}
      <div className="rail-titles"><h3 className="rail-title">{title}</h3>{sub && <span className="rail-sub">{sub}</span>}</div>
      {onSeeAll && <button className="rail-all" onClick={(e) => { e.stopPropagation(); onSeeAll(); }}>See all <span aria-hidden="true">→</span></button>}
    </div>
  );
}

function FusionShowcase({ all, seen, holo, onOpen, openCat }) {
  const [spot, setSpot] = useSF("Fire");
  const byRole = useMF(() => {
    const g = {};
    window.ROLE_ORDER.forEach((k) => { g[k] = []; });
    all.forEach((f) => { const k = window.ARCH_TO_ROLE[f.archetype]; if (g[k]) g[k].push(f); });
    Object.keys(g).forEach((k) => g[k].sort((a, b) => b.bst - a.bst));
    return g;
  }, [all]);
  const topBst = useMF(() => [...all].sort((a, b) => b.bst - a.bst), [all]);
  const sigSpot = useMF(() => [...all].sort((a, b) => b.signatureAxis.length - a.signatureAxis.length), [all]);
  const spotList = useMF(() => all.filter((f) => f.types.includes(spot)).sort((a, b) => b.bst - a.bst), [all, spot]);

  let railNum = 0;
  return (
    <div className="showcase">
      <div className="show-label"><span className="mono">01</span> Browse by role <span className="show-label-sub">— the spine of the dex</span></div>
      {window.ROLE_ORDER.map((k) => {
        const r = window.ROLES[k]; const items = byRole[k] || [];
        if (!items.length) return null; railNum++;
        return (
          <section className="rail-sec" key={k}>
            <RailHead num={"R" + String(railNum).padStart(2, "0")} color={r.color} glyph={r.glyph} title={r.label}
              sub={`${(byRole[k] || []).length} fusions`} onSeeAll={() => openCat({ title: r.label, color: r.color, glyph: r.glyph, items: byRole[k] || [] })} />
            <Rail items={items} holo={holo} seen={seen} onOpen={onOpen} />
          </section>
        );
      })}

      <div className="show-label"><span className="mono">02</span> Browse by type</div>
      <div className="type-row">
        {window.TYPE_LIST.map((t) => (
          <button key={t} className={"type-pill" + (spot === t ? " on" : "")} style={{ "--tc": `var(--type-${t.toLowerCase()})` }}
            aria-pressed={spot === t} onClick={() => setSpot(t)}>{t}</button>
        ))}
      </div>
      <section className="rail-sec">
        <RailHead num="" color={`var(--type-${spot.toLowerCase()})`} title={`${spot} spotlight`} sub={`${all.filter((f) => f.types.includes(spot)).length} ${spot}-types`} onSeeAll={() => openCat({ title: `${spot}-type fusions`, color: `var(--type-${spot.toLowerCase()})`, items: all.filter((f) => f.types.includes(spot)).sort((a, b) => b.bst - a.bst) })} />
        {spotList.length ? <Rail items={spotList} holo={holo} seen={seen} onOpen={onOpen} />
          : <div className="rail-empty">No {spot}-type fusions loaded in this sample.</div>}
      </section>

      <div className="show-label"><span className="mono">03</span> Signature spotlight <span className="show-label-sub">— what's your win condition?</span>
        <button className="show-all" onClick={() => openCat({ title: "Signature Spotlight", color: "var(--glow)", items: [...all].sort((a, b) => b.signatureAxis.length - a.signatureAxis.length) })}>See all →</button></div>
      <section className="rail-sec">
        <Rail items={sigSpot} holo={holo} seen={seen} onOpen={onOpen} caption={(f) => f.signatureAxis} />
      </section>

      <div className="show-label"><span className="mono">04</span> Raw power <span className="show-label-sub">— absolute units</span>
        <button className="show-all" onClick={() => openCat({ title: "Absolute Units", color: "var(--glow)", items: [...all].sort((a, b) => b.bst - a.bst) })}>See all →</button></div>
      <section className="rail-sec">
        <Rail items={topBst} holo={holo} seen={seen} onOpen={onOpen} caption={(f) => `${f.bst} BST`} />
      </section>
    </div>
  );
}

// ── Pager (windowed; reuses .rolechip styling) ──────────────────────────────
function Pager({ page, pageCount, onPage, total, pageSize }) {
  if (pageCount <= 1) return null;
  const from = (page - 1) * pageSize + 1, to = Math.min(total, page * pageSize);
  const pages = []; for (let p = Math.max(1, page - 2); p <= Math.min(pageCount, page + 2); p++) pages.push(p);
  return (
    <div className="pager" style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 8, flexWrap: "wrap", padding: "calc(var(--u)*6) 0 calc(var(--u)*4)" }}>
      <button className="rolechip" disabled={page <= 1} onClick={() => onPage(page - 1)} style={{ opacity: page <= 1 ? .4 : 1 }}>‹ Prev</button>
      {pages[0] > 1 && <span style={{ color: "var(--ink-3)" }}>…</span>}
      {pages.map((p) => <button key={p} className="rolechip" aria-pressed={p === page} onClick={() => onPage(p)} style={{ minWidth: 34, justifyContent: "center", fontWeight: p === page ? 800 : 600 }}>{p}</button>)}
      {pages[pages.length - 1] < pageCount && <span style={{ color: "var(--ink-3)" }}>…</span>}
      <button className="rolechip" disabled={page >= pageCount} onClick={() => onPage(page + 1)} style={{ opacity: page >= pageCount ? .4 : 1 }}>Next ›</button>
      <span style={{ color: "var(--ink-3)", fontSize: 12, marginLeft: 8 }}>{from.toLocaleString()}–{to.toLocaleString()} of {total.toLocaleString()}</span>
    </div>
  );
}

function FusionsView({ seen, mark, holo = true }) {
  const all = window.FUSIONS;
  const [q, setQ] = useSF(""); const [head, setHead] = useSF(""); const [body, setBody] = useSF("");
  const [type, setType] = useSF(""); const [role, setRole] = useSF(""); const [open, setOpen] = useSF(null);
  const [cat, setCat] = useSF(null);
  const [filtering, setFiltering] = useSF(false);
  const [page, setPage] = useSF(1);
  const hasFilter = !!(q || head || body || type || role);

  const heads = useMF(() => [...new Set(all.map((f) => f.headName))].sort(), [all]);
  const bodies = useMF(() => [...new Set(all.map((f) => f.bodyName))].sort(), [all]);

  // animate grid on filter CHANGE only (skip first mount so initial paint is visible)
  const mounted = useRF(false);
  useEF(() => {
    if (!mounted.current) { mounted.current = true; return; }
    if (window.prefersReduced()) return;
    setFiltering(true); const t = setTimeout(() => setFiltering(false), 220); return () => clearTimeout(t);
  }, [q, head, body, type, role]);

  const tokens = useMF(() => q.trim().toLowerCase().split(/\s+/).filter(Boolean), [q]);
  const list = useMF(() => all.filter((f) => {
    if (head && f.headName !== head) return false;
    if (body && f.bodyName !== body) return false;
    if (type && !f.types.includes(type)) return false;
    if (role && window.ARCH_TO_ROLE[f.archetype] !== role) return false;
    if (tokens.length) {
      const hay = f._hay || `${f.name} ${f.headName} ${f.bodyName} ${f.ability}`.toLowerCase();
      for (let i = 0; i < tokens.length; i++) if (!hay.includes(tokens[i])) return false;
    }
    return true;
  }), [all, tokens, head, body, type, role]);

  useEF(() => { setPage(1); }, [q, head, body, type, role, cat]);

  // Slim index rows hydrate to the full record (movepool/learnset) before the detail opens.
  const hydrate = (f) => (!f || !f._slim) ? Promise.resolve(f)
    : window.IF.loadHead(f.headId).then((l) => l.find((x) => x.bodyId === f.bodyId) || f).catch(() => f);
  const onOpen = (f) => { mark(window.fusionKey(f)); hydrate(f).then((full) => setOpen(full)); };
  const clearAll = () => { setQ(""); setHead(""); setBody(""); setType(""); setRole(""); setCat(null); };

  const PAGE_SIZE = 60;
  const activeList = hasFilter ? list : cat ? cat.items : null;
  const pageCount = activeList ? Math.max(1, Math.ceil(activeList.length / PAGE_SIZE)) : 1;
  const shown = activeList ? activeList.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE) : [];

  return (
    <div className="view">
      <div className="filterbar">
        {(hasFilter || cat) && <button className="browse-back" onClick={clearAll}><window.IcoChevron s={14} /> Browse</button>}
        <div className="search"><window.IcoSearch s={16} />
          <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search every fusion — name, parent, ability, move…" /></div>
        <Dropdown value={head} onChange={setHead} options={heads} placeholder="Head" />
        <Dropdown value={body} onChange={setBody} options={bodies} placeholder="Body" />
        <Dropdown value={type} onChange={setType} options={window.TYPE_LIST} placeholder="Type" />
        <span className="count">{hasFilter ? <><b>{list.length.toLocaleString()}</b> match</> : <><b>{all.length.toLocaleString()}</b> fusions · {window.TYPE_LIST.length} types</>}</span>
        <div className="rolebar">
          <button className={"rolechip all"} aria-pressed={role === ""} onClick={() => setRole("")}>All roles</button>
          {window.ROLE_ORDER.map((k) => {
            const r = window.ROLES[k];
            return <button key={k} className="rolechip" style={{ "--rc": r.color }} aria-pressed={role === k} onClick={() => setRole(role === k ? "" : k)}>
              <span className="rc-glyph">{r.glyph}</span>{r.label}</button>;
          })}
        </div>
      </div>

      <div className="view-scroll scrl">
        {hasFilter ? (
          <div className="pad">
            {list.length === 0 ? (
              <div className="empty"><div className="pokeball" style={{ animation: "none" }} /><h3>No fusions match</h3><p>Try another name, parent, ability, move, type, or role.</p></div>
            ) : (
              <>
                <div className="fgrid" data-filtering={filtering ? "true" : "false"}>
                  {shown.map((f, i) => <FusionCard key={f.sprite} f={f} idx={i} holo={holo} seen={seen.has(window.fusionKey(f))} onOpen={onOpen} />)}
                </div>
                <Pager page={page} pageCount={pageCount} onPage={setPage} total={list.length} pageSize={PAGE_SIZE} />
              </>
            )}
          </div>
        ) : cat ? (
          <div className="pad">
            <div className="cat-head" style={{ "--rc": cat.color }}>
              <button className="browse-back" onClick={() => setCat(null)}><window.IcoChevron s={14} /> Browse</button>
              {cat.glyph && <span className="rail-glyph">{cat.glyph}</span>}
              <h2 className="cat-title">{cat.title}</h2>
              <span className="cat-count">{cat.items.length.toLocaleString()} fusions</span>
            </div>
            <div className="fgrid">
              {shown.map((f, i) => <FusionCard key={f.sprite} f={f} idx={i} holo={holo} seen={seen.has(window.fusionKey(f))} onOpen={onOpen} />)}
            </div>
            <Pager page={page} pageCount={pageCount} onPage={setPage} total={cat.items.length} pageSize={PAGE_SIZE} />
          </div>
        ) : (
          <div className="pad"><FusionShowcase all={all} seen={seen} holo={holo} onOpen={onOpen} openCat={setCat} /></div>
        )}
      </div>

      {open && <FusionDetail fusion={open} siblings={hasFilter ? list : cat ? cat.items : all} onPick={onOpen} onClose={() => setOpen(null)} />}
    </div>
  );
}

Object.assign(window, { FusionsView, FusionCard, FusionDetail });
