/* Draft + Leaderboard + Teams + AllPlayers, wired to the live API. */

const POS_FILTERS = ["ALL", "GK", "DF", "MF", "FW"];

function useFilters() {
  const [pos, setPos] = React.useState("ALL");
  const [country, setCountry] = React.useState("ALL");
  const [q, setQ] = React.useState("");
  const [availOnly, setAvailOnlyRaw] = React.useState(false);
  const [draftedOnly, setDraftedOnlyRaw] = React.useState(false);
  // Mutually exclusive: turning one on turns the other off.
  const setAvailOnly = (v) => { setAvailOnlyRaw(v); if (v) setDraftedOnlyRaw(false); };
  const setDraftedOnly = (v) => { setDraftedOnlyRaw(v); if (v) setAvailOnlyRaw(false); };
  return { pos, setPos, country, setCountry, q, setQ, availOnly, setAvailOnly, draftedOnly, setDraftedOnly };
}

function FilterBar({ f, showAvail, countries }) {
  return (
    <div className="row gap-3 wrap-flex" style={{ marginBottom: 18 }}>
      <div className="seg">
        {POS_FILTERS.map((p) => (
          <button key={p} className={f.pos === p ? "on" : ""} onClick={() => f.setPos(p)}>{p === "ALL" ? "All" : p}</button>
        ))}
      </div>
      <select className="field" style={{ width: "auto", minWidth: 150, paddingRight: 8 }} value={f.country} onChange={(e) => f.setCountry(e.target.value)}>
        <option value="ALL">All nations</option>
        {countries.map((c) => <option key={c} value={c}>{c}</option>)}
      </select>
      <input className="field" style={{ width: "auto", flex: 1, minWidth: 160 }} placeholder="Search players…" value={f.q} onChange={(e) => f.setQ(e.target.value)} />
      {showAvail && (
        <>
          <button className={"btn btn-sm " + (f.availOnly ? "btn-primary" : "btn-soft")} onClick={() => f.setAvailOnly(!f.availOnly)}>
            {f.availOnly ? "✓ " : ""}Available only
          </button>
          <button className={"btn btn-sm " + (f.draftedOnly ? "btn-primary" : "btn-soft")} onClick={() => f.setDraftedOnly(!f.draftedOnly)}>
            {f.draftedOnly ? "✓ " : ""}Drafted only
          </button>
        </>
      )}
    </div>
  );
}

function applyFilters(players, f) {
  return players.filter((p) => {
    if (f.pos !== "ALL" && p.pos !== f.pos) return false;
    if (f.country !== "ALL" && p.country !== f.country) return false;
    if (f.availOnly && p.drafted_by) return false;
    if (f.draftedOnly && !p.drafted_by) return false;
    if (f.q && !(p.name + " " + p.club + " " + p.country).toLowerCase().includes(f.q.toLowerCase())) return false;
    return true;
  });
}

/* ============== DRAFT ============== */

function OnClockBanner({ onClock, round, overall, total, done }) {
  if (done) {
    return (
      <div className="card" style={{ padding: "18px 22px", marginBottom: 20, borderColor: "var(--accent)" }}>
        <div className="row between wrap-flex" style={{ gap: 12 }}>
          <div className="row gap-3"><Crest size={34} /><div className="col"><span className="kicker">Draft complete</span><span className="display" style={{ fontSize: 26 }}>Every seat is full — let the tournament decide</span></div></div>
        </div>
      </div>
    );
  }
  const yours = onClock.you;
  return (
    <div className={"card " + (yours ? "on-clock" : "")} style={{ padding: "16px 22px", marginBottom: 20, borderColor: yours ? "var(--accent)" : "var(--line)" }}>
      <div className="row between wrap-flex" style={{ gap: 14 }}>
        <div className="row gap-3">
          <ManagerDot m={onClock} size={46} ring />
          <div className="col" style={{ gap: 2 }}>
            <span className="kicker" style={{ whiteSpace: "nowrap" }}>On the clock · Round {round}</span>
            <span className="display" style={{ fontSize: 28 }}>
              {yours ? "You're up — make your pick" : onClock.name + " is picking…"}
            </span>
          </div>
        </div>
        <div className="row gap-2" style={{ alignItems: "baseline", whiteSpace: "nowrap" }}>
          <span className="kicker" style={{ fontSize: 11 }}>PICK</span>
          <span className="display num" style={{ fontSize: 30 }}>#{overall + 1}</span>
          <span className="kicker" style={{ fontSize: 11, color: "var(--muted)" }}>OF</span>
          <span className="display num" style={{ fontSize: 30, color: "var(--muted)" }}>{total}</span>
        </div>
      </div>
    </div>
  );
}

function PlayerDraftCard({ p, takenBy, canPick, onPick }) {
  return (
    <div className="panel pop" style={{ padding: 16, opacity: takenBy ? .62 : 1 }}>
      <div className="row gap-3" style={{ marginBottom: 12 }}>
        <PlayerAvatar player={p} size={46} />
        <div className="col" style={{ gap: 2, minWidth: 0, flex: 1 }}>
          <div className="row gap-2" style={{ minWidth: 0 }}>
            <b style={{ fontSize: 17, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{p.name}</b>
            <PosPill pos={p.pos} />
          </div>
          <span style={{ fontSize: 13.5, color: "var(--muted)" }}><Flag country={p.country} size={14} /> {p.country} · {p.club}</span>
        </div>
      </div>
      <div className="row between">
        <div className="row gap-4">
          <span style={{ fontSize: 13, color: "var(--muted)" }}>G <b className="num" style={{ color: "var(--text)", fontSize: 16 }}>{p.g}</b></span>
          <span style={{ fontSize: 13, color: "var(--muted)" }}>A <b className="num" style={{ color: "var(--text)", fontSize: 16 }}>{p.a}</b></span>
          <span style={{ fontSize: 13, color: "var(--muted)" }}>PTS <b className="num" style={{ color: "var(--accent-2)", fontSize: 16 }}>{p.pts.toFixed(1)}</b></span>
        </div>
        {takenBy
          ? <span className="chip" style={{ borderColor: takenBy.color }}><span className="dot" style={{ background: takenBy.color }}></span>{takenBy.name}</span>
          : <button className="btn btn-sm btn-primary" disabled={!canPick} onClick={() => onPick(p.id)}>Draft</button>}
      </div>
    </div>
  );
}

// Snake math, mirrored from functions/api/_utils.js — round 0 = 0..n-1, round 1 = n-1..0.
function memberIdxAtPick(p, n) {
  const round = Math.floor(p / n);
  const idxInRound = p % n;
  return round % 2 === 0 ? idxInRound : n - 1 - idxInRound;
}

function NextFivePicksCard({ draft }) {
  const upcoming = React.useMemo(() => {
    if (draft.done || !draft.order || draft.order.length === 0) return [];
    const n = draft.order.length;
    const out = [];
    for (let p = draft.overall; p < Math.min(draft.overall + 5, draft.total); p++) {
      out.push({ pickNumber: p, round: Math.floor(p / n) + 1, manager: draft.order[memberIdxAtPick(p, n)] });
    }
    return out;
  }, [draft.order, draft.overall, draft.total, draft.done]);

  if (upcoming.length === 0) return null;

  return (
    <div className="card" style={{ padding: 16, marginBottom: 16 }}>
      <span className="kicker" style={{ display: "block", marginBottom: 10 }}>Next 5 picks</span>
      <div className="row gap-2 wrap-flex">
        {upcoming.map((u, i) => {
          const isClock = i === 0;
          return (
            <div key={u.pickNumber} className="row gap-2 panel" style={{ padding: "6px 12px 6px 8px", borderRadius: 999, background: isClock ? "color-mix(in oklch, var(--accent) 14%, transparent)" : "transparent", borderColor: isClock ? "var(--accent)" : "var(--line)" }}>
              <span className="display num" style={{ color: "var(--faint)", fontSize: 12 }}>#{u.pickNumber + 1}</span>
              <ManagerDot m={u.manager} size={22} />
              <span style={{ fontSize: 14, whiteSpace: "nowrap" }}>{u.manager.name}{u.manager.you ? " (you)" : ""}</span>
              <span style={{ fontSize: 11, color: "var(--faint)" }}>R{u.round}</span>
              {isClock && <span className="live-dot"></span>}
            </div>
          );
        })}
      </div>
    </div>
  );
}

function FullDraftOrderDetails({ draft }) {
  if (!draft.order || draft.order.length === 0) return null;
  const n = draft.order.length;
  const total = draft.total;
  // Group all picks into rounds for display.
  const rounds = [];
  for (let p = 0; p < total; p++) {
    const round = Math.floor(p / n);
    if (!rounds[round]) rounds[round] = [];
    rounds[round].push({ pickNumber: p, manager: draft.order[memberIdxAtPick(p, n)] });
  }
  const rosterSize = Math.ceil(total / n);
  return (
    <details className="card" style={{ padding: 0, overflow: "hidden" }}>
      <summary style={{ padding: 16, cursor: "pointer", listStyle: "none", userSelect: "none", display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12 }}>
        <span className="kicker">View full draft order</span>
        <span style={{ color: "var(--muted)", fontSize: 13 }}>{n} managers · {rosterSize} rounds</span>
      </summary>
      <div style={{ padding: "0 16px 16px", borderTop: "1px solid var(--line-soft)" }}>
        {rounds.map((round, r) => (
          <div key={r} style={{ marginTop: 14 }}>
            <span className="kicker" style={{ display: "block", marginBottom: 8, fontSize: 11 }}>Round {r + 1}{r % 2 === 1 ? " (reverse)" : ""}</span>
            <div className="col gap-1">
              {round.map((p) => {
                const isCurrent = p.pickNumber === draft.overall && !draft.done;
                const isPast = p.pickNumber < draft.overall;
                return (
                  <div key={p.pickNumber} className="row gap-3" style={{ padding: "5px 8px", borderRadius: 8, background: isCurrent ? "color-mix(in oklch, var(--accent) 14%, transparent)" : "transparent", opacity: isPast ? 0.5 : 1 }}>
                    <span className="display num" style={{ width: 36, color: "var(--faint)", fontSize: 13 }}>#{p.pickNumber + 1}</span>
                    <ManagerDot m={p.manager} size={22} />
                    <b style={{ flex: 1, fontSize: 14 }}>{p.manager.name}{p.manager.you ? " (you)" : ""}</b>
                    {isCurrent && <span className="live-dot"></span>}
                  </div>
                );
              })}
            </div>
          </div>
        ))}
      </div>
    </details>
  );
}

function DraftSidebar({ leagueState, players }) {
  const { managers, draft, picks } = leagueState;
  const byId = React.useMemo(() => Object.fromEntries(players.map(p => [p.id, p])), [players]);
  const mById = React.useMemo(() => Object.fromEntries(managers.map(m => [m.id, m])), [managers]);
  const recent = picks.slice(-7).reverse();

  return (
    <div className="col gap-4" style={{ position: "sticky", top: 80 }}>
      <div className="card" style={{ padding: 18 }}>
        <span className="kicker" style={{ display: "block", marginBottom: 12 }}>Recent picks</span>
        {recent.length === 0 && <p style={{ color: "var(--faint)", fontSize: 14, margin: 0 }}>No picks yet.</p>}
        <div className="col gap-2">
          {recent.map((pk) => {
            const p = byId[pk.player_id]; const m = mById[pk.member_id];
            if (!p || !m) return null;
            return (
              <div key={pk.pick_number} className="row gap-3" style={{ animation: "slideIn .3s var(--ease) both" }}>
                <span className="display num" style={{ width: 28, color: "var(--faint)", fontSize: 14 }}>#{pk.pick_number + 1}</span>
                <ManagerDot m={m} size={22} />
                <span style={{ flex: 1, fontSize: 14, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{p.name}</span>
                <PosPill pos={p.pos} />
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

function Draft({ leagueState, players, pickPlayer, onReset }) {
  const f = useFilters();
  const { draft, managers } = leagueState;
  const me = managers.find((m) => m.you);
  const isHost = managers.length > 0 && managers[0].you;
  const canPick = !draft.done && me && draft.onClock && draft.onClock.id === me.id;
  const countries = React.useMemo(() => [...new Set(players.map((p) => p.country))].sort(), [players]);
  const filtered = applyFilters(players, f);
  const mById = React.useMemo(() => Object.fromEntries(managers.map(m => [m.id, m])), [managers]);
  const [pickErr, setPickErr] = React.useState(null);

  const handlePick = async (playerId) => {
    setPickErr(null);
    try { await pickPlayer(playerId); } catch (e) { setPickErr(e.message); }
  };

  return (
    <div className="wrap" style={{ paddingTop: 30, paddingBottom: 92 }}>
      <OnClockBanner onClock={draft.onClock} round={draft.round} overall={draft.overall} total={draft.total} done={draft.done} />
      <NextFivePicksCard draft={draft} />
      <div style={{ marginBottom: 16 }}><FullDraftOrderDetails draft={draft} /></div>
      {pickErr && <div className="panel" style={{ padding: 12, marginBottom: 16, borderColor: "var(--fw)" }}><b style={{ color: "var(--fw)" }}>Couldn't draft: </b><span style={{ color: "var(--text)" }}>{pickErr}</span></div>}
      <div style={{ display: "grid", gridTemplateColumns: "minmax(0,1fr) 300px", gap: 26, alignItems: "start" }} className="draft-grid">
        <div>
          <FilterBar f={f} showAvail countries={countries} />
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill,minmax(300px,1fr))", gap: 14 }}>
            {filtered.slice(0, 200).map((p) => (
              <PlayerDraftCard key={p.id} p={p}
                takenBy={p.drafted_by ? mById[p.drafted_by] : null}
                canPick={canPick} onPick={handlePick} />
            ))}
          </div>
          {filtered.length > 200 && (
            <p style={{ color: "var(--muted)", fontSize: 14, marginTop: 20, textAlign: "center" }}>
              Showing top 200 of {filtered.length}. Narrow with filters.
            </p>
          )}
        </div>
        <DraftSidebar leagueState={leagueState} players={players} />
      </div>

      {isHost && onReset && (
        <div style={{ marginTop: 40, paddingTop: 20, borderTop: "1px solid var(--line)", display: "flex", gap: 12, flexWrap: "wrap" }}>
          <span className="kicker" style={{ width: "100%", marginBottom: 4 }}>Commissioner</span>
          <button className="btn btn-soft btn-sm" onClick={() => onReset("draft")}>↺ Re-randomize draft order</button>
          <button className="btn btn-soft btn-sm" style={{ color: "var(--fw)" }} onClick={() => onReset("full")}>⚠ Full reset to lobby</button>
        </div>
      )}
    </div>
  );
}

/* ============== LEADERBOARD ============== */

function Leaderboard({ leagueState, players, go }) {
  const { managers, picks } = leagueState;
  const byId = React.useMemo(() => Object.fromEntries(players.map(p => [p.id, p])), [players]);

  // Click a manager name to jump to their team card on the Teams tab.
  const openTeam = (memberId) => {
    location.hash = "team-" + memberId;
    if (typeof go === "function") go("teams");
  };

  const rows = managers.map((m) => {
    const roster = picks.filter((pk) => pk.member_id === m.id).map((pk) => byId[pk.player_id]).filter(Boolean);
    const g = roster.reduce((s, p) => s + p.g, 0);
    const a = roster.reduce((s, p) => s + p.a, 0);
    const gwg = roster.reduce((s, p) => s + (p.gwg || 0), 0);
    const top = [...roster].sort((x, y) => y.pts - x.pts)[0];
    return { m, roster, g, a, gwg, pts: g + a * 0.5 + gwg, top };
  }).sort((x, y) => y.pts - x.pts)
    .map((r, i) => ({ ...r, rank: i + 1 })); // 1-indexed default rank (by pts desc)

  const leader = rows[0];

  // Sortable headers — default pts desc, cycle desc → asc → reset.
  const [sort, setSort] = React.useState({ key: "pts", dir: "desc" });
  const cycleSort = (key) => setSort((prev) => {
    if (prev.key !== key) return { key, dir: "desc" };
    if (prev.dir === "desc") return { key, dir: "asc" };
    return { key: "pts", dir: "desc" };
  });
  const sortedRows = React.useMemo(() => {
    if (sort.key === "pts" && sort.dir === "desc") return rows;
    const d = sort.dir === "asc" ? 1 : -1;
    return [...rows].sort((x, y) => {
      if (sort.key === "manager") return x.m.name.localeCompare(y.m.name) * d;
      if (sort.key === "rank")    return (x.rank - y.rank) * d;
      if (sort.key === "top")     return (((x.top && x.top.pts) || 0) - ((y.top && y.top.pts) || 0)) * d;
      return ((x[sort.key] || 0) - (y[sort.key] || 0)) * d;
    });
  }, [rows, sort.key, sort.dir]);

  const SortableTh = ({ k, label, className, title, style }) => {
    const active = sort.key === k;
    const arrow = active ? (sort.dir === "asc" ? " ↑" : " ↓") : "";
    return (
      <th
        className={className}
        title={title || ""}
        onClick={() => cycleSort(k)}
        style={{ cursor: "pointer", userSelect: "none", color: active ? "var(--text)" : undefined, ...(style || {}) }}
      >
        {label}{arrow}
      </th>
    );
  };

  if (!leader || picks.length === 0) {
    return (
      <div className="wrap" style={{ paddingTop: 60, paddingBottom: 80, textAlign: "center" }}>
        <Crest size={48} />
        <h2 className="display" style={{ fontSize: 40, marginTop: 16 }}>No standings yet</h2>
        <p style={{ color: "var(--muted)", fontSize: 18 }}>Run the draft to start banking points.</p>
      </div>
    );
  }

  return (
    <div className="wrap" style={{ paddingTop: 30, paddingBottom: 92 }}>
      <SectionTitle title="Table" />
      <div className="card" style={{ padding: 26, marginBottom: 22, background: "var(--pitch-img)" }}>
        <div className="row between wrap-flex" style={{ gap: 18 }}>
          <div className="row gap-4">
            <div className="display num" style={{ fontSize: 64, color: "var(--accent-2)", lineHeight: .8 }}>1</div>
            <div className="col" style={{ gap: 4 }}>
              <span className="kicker">League leader</span>
              <div className="row gap-3"><ManagerDot m={leader.m} size={40} /><span className="display" style={{ fontSize: 40 }}>{leader.m.name}</span></div>
              {leader.top && <span style={{ color: "var(--muted)" }}>Carried by <b style={{ color: "var(--text)" }}>{leader.top.name}</b> ({leader.top.pts.toFixed(1)} pts)</span>}
            </div>
          </div>
          <StatBlock label="Points" value={leader.pts.toFixed(1)} accent="var(--accent-2)" />
        </div>
      </div>
      <div className="row gap-2 wrap-flex" style={{ marginBottom: 14 }}>
        <span className="kicker" style={{ marginRight: 6 }}>Scoring</span>
        <span className="chip"><b className="num" style={{ color: "var(--fw)" }}>1.0</b>&nbsp;pt&nbsp;/&nbsp;goal</span>
        <span className="chip"><b className="num" style={{ color: "var(--df)" }}>0.5</b>&nbsp;pt&nbsp;/&nbsp;assist</span>
        <span className="chip"><b className="num" style={{ color: "var(--accent-2)" }}>+1</b>&nbsp;GWG&nbsp;bonus</span>
      </div>
      <div className="card" style={{ overflow: "hidden" }}>
        <table className="tbl tbl-leaderboard">
          <thead><tr>
            <SortableTh k="rank"    label="#"   className="col-rank" style={{ width: 50 }} />
            <SortableTh k="manager" label="Manager" />
            <SortableTh k="g"   label="G"   className="center col-stat" />
            <SortableTh k="a"   label="A"   className="center col-stat" />
            <SortableTh k="gwg" label="GWG" className="center col-stat" title="Game-winning goals · +1 each" />
            <SortableTh k="top" label="Top player" className="hide-sm" />
            <SortableTh k="pts" label="Pts" className="right col-points" />
          </tr></thead>
          <tbody>
            {sortedRows.map((r) => (
              <tr key={r.m.id} style={{ background: r.m.you ? "color-mix(in oklch, var(--accent) 9%, transparent)" : "transparent" }}>
                <td><span className="display num" style={{ fontSize: 22, color: r.rank === 1 ? "var(--accent-2)" : "var(--faint)" }}>{r.rank}</span></td>
                <td>
                  <button
                    onClick={() => openTeam(r.m.id)}
                    title={"View " + r.m.name + "'s team"}
                    className="row gap-3"
                    style={{ background: "none", border: "none", padding: 0, cursor: "pointer", textAlign: "left", color: "inherit", font: "inherit" }}
                  >
                    <ManagerDot m={r.m} size={30} />
                    <b className="mgr-name" style={{ textDecoration: "underline", textDecorationColor: "var(--line)", textUnderlineOffset: 3 }}>{r.m.name}</b>
                    {r.m.you && <span className="chip hide-sm" style={{ padding: "2px 8px", fontSize: 11 }}>you</span>}
                  </button>
                </td>
                <td className="center num">{r.g}</td>
                <td className="center num">{r.a}</td>
                <td className="center num" style={{ color: r.gwg ? "var(--accent-2)" : "var(--faint)" }}>{r.gwg}</td>
                <td className="hide-sm">{r.top ? <span style={{ fontSize: 14, color: "var(--muted)" }}><Flag country={r.top.country} size={14} /> {r.top.name}</span> : "—"}</td>
                <td className="right num display" style={{ fontSize: 22, color: "var(--accent-2)" }}>{r.pts.toFixed(1)}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

/* ============== TEAMS ============== */

// Inline player list with sortable columns. Each card owns its own sort state.
function TeamRosterCard({ row, draftPosition }) {
  const [sort, setSort] = React.useState({ key: "pts", dir: "desc" });
  const cycleSort = (key) => setSort((prev) => {
    if (prev.key !== key) return { key, dir: "desc" };
    if (prev.dir === "desc") return { key, dir: "asc" };
    return { key: "pts", dir: "desc" }; // 3rd click → default
  });
  const sorted = React.useMemo(() => {
    const dir = sort.dir === "asc" ? 1 : -1;
    return [...row.roster].sort((x, y) => ((x[sort.key] || 0) - (y[sort.key] || 0)) * dir);
  }, [row.roster, sort.key, sort.dir]);

  const Sortable = ({ k, label, width, className }) => {
    const active = sort.key === k;
    const arrow = active ? (sort.dir === "asc" ? " ↑" : " ↓") : "";
    return (
      <span className={className} onClick={() => cycleSort(k)} style={{
        cursor: "pointer", userSelect: "none",
        width, textAlign: "center", fontSize: 10, letterSpacing: ".06em",
        textTransform: "uppercase", color: active ? "var(--text)" : "var(--faint)",
        fontFamily: "var(--font-display)", fontWeight: 700,
      }}>{label}{arrow}</span>
    );
  };

  return (
    <div id={"team-" + row.m.id} className="card" style={{ padding: 20, borderTop: `4px solid ${row.m.color}`, transition: "box-shadow .25s", scrollMarginTop: 80 }}>
      <div className="row between" style={{ marginBottom: 14 }}>
        <div className="row gap-3">
          <ManagerDot m={row.m} size={36} />
          <div className="col">
            <b style={{ fontSize: 18 }}>{row.m.name}</b>
            <span style={{ fontSize: 12, color: "var(--muted)" }}>
              {row.roster.length} players{draftPosition ? ` · pick #${draftPosition}` : ""}
            </span>
          </div>
        </div>
        <StatBlock label="Pts" value={row.pts.toFixed(1)} accent="var(--accent-2)" />
      </div>

      <div className="row" style={{ padding: "4px 0 6px", borderBottom: "1px solid var(--line-soft)", marginBottom: 4, gap: 6 }}>
        <span style={{ flex: 1, fontSize: 10, color: "var(--faint)", textTransform: "uppercase", letterSpacing: ".06em", fontFamily: "var(--font-display)", fontWeight: 700 }}>Player</span>
        <Sortable k="g"   label="G"   width={22} />
        <Sortable k="a"   label="A"   width={22} />
        <Sortable k="gwg" label="GWG" width={32} />
        <Sortable k="pts" label="Pts" width={36} className="team-pts-pad" />
      </div>

      <div className="col gap-1">
        {sorted.map((p) => (
          <div key={p.id} className="row" style={{ padding: "5px 0", borderBottom: "1px solid var(--line-soft)", gap: 6 }}>
            <div className="row gap-2" style={{ flex: 1, minWidth: 0 }}>
              <PosPill pos={p.pos} />
              <Flag country={p.country} size={13} />
              <span style={{ whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", fontSize: 13 }}>{p.name}</span>
            </div>
            <span className="num" style={{ width: 22, textAlign: "center", fontSize: 13, color: "var(--muted)" }}>{p.g}</span>
            <span className="num" style={{ width: 22, textAlign: "center", fontSize: 13, color: "var(--muted)" }}>{p.a}</span>
            <span className="num" style={{ width: 32, textAlign: "center", fontSize: 13, color: p.gwg ? "var(--accent-2)" : "var(--faint)" }}>{p.gwg || 0}</span>
            <span className="num team-pts-pad" style={{ width: 36, textAlign: "right", fontSize: 13, color: "var(--accent-2)", fontWeight: 700 }}>{p.pts.toFixed(1)}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

function Teams({ leagueState, players }) {
  const { managers, picks, league, draft } = leagueState;
  const byId = React.useMemo(() => Object.fromEntries(players.map(p => [p.id, p])), [players]);
  const draftOrder = draft && draft.order ? draft.order : [];
  const draftPositionById = React.useMemo(
    () => Object.fromEntries(draftOrder.map((m, i) => [m.id, i + 1])),
    [draftOrder]
  );

  // If we arrived via Leaderboard with a #team-<id> hash, scroll to that card
  // once it renders. Effect must be unconditional (Rules of Hooks).
  React.useEffect(() => {
    if (!picks.length) return;
    const hash = location.hash;
    if (!hash || !hash.startsWith("#team-")) return;
    const el = document.getElementById(hash.slice(1));
    if (!el) return;
    requestAnimationFrame(() => {
      el.scrollIntoView({ behavior: "smooth", block: "start" });
      el.style.boxShadow = "0 0 0 2px var(--accent)";
      setTimeout(() => { el.style.boxShadow = ""; }, 1800);
      history.replaceState(null, "", location.pathname);
    });
  }, [picks.length]);

  if (picks.length === 0) {
    const meEmpty = managers.find((m) => m.you);
    return (
      <div className="wrap" style={{ paddingTop: 60, paddingBottom: 80, textAlign: "center" }}>
        <Crest size={48} />
        <h2 className="display" style={{ fontSize: 40, marginTop: 16 }}>No squads yet</h2>
        <p style={{ color: "var(--muted)", fontSize: 18 }}>Run the draft to build the rosters.</p>
        {meEmpty && (
          <div className="row gap-2 wrap-flex" style={{ justifyContent: "center", marginTop: 24 }}>
            {window.SetPinButton && <window.SetPinButton leagueId={league.id} memberId={meEmpty.id} hasPin={meEmpty.has_pin} />}
            {window.RenameButton && <window.RenameButton leagueId={league.id} memberId={meEmpty.id} currentName={meEmpty.name} />}
          </div>
        )}
      </div>
    );
  }

  const rows = managers.map((m) => {
    const roster = picks.filter((pk) => pk.member_id === m.id).map((pk) => byId[pk.player_id]).filter(Boolean);
    const g = roster.reduce((s, p) => s + p.g, 0);
    const a = roster.reduce((s, p) => s + p.a, 0);
    const gwg = roster.reduce((s, p) => s + (p.gwg || 0), 0);
    return { m, roster, pts: g + a * 0.5 + gwg };
  }).sort((x, y) => y.pts - x.pts);

  const me = managers.find((m) => m.you);

  return (
    <div className="wrap" style={{ paddingTop: 30, paddingBottom: 92 }}>
      <SectionTitle title="Squads" />

      {me && (
        <div className="card row between wrap-flex" style={{ padding: "14px 18px", marginBottom: 18, gap: 12 }}>
          <div className="row gap-3" style={{ minWidth: 0 }}>
            <ManagerDot m={me} size={32} />
            <div className="col" style={{ gap: 1, minWidth: 0 }}>
              <b style={{ fontSize: 15 }}>{me.name} <span style={{ color: "var(--muted)", fontWeight: 400, fontSize: 13 }}>· you</span></b>
              <span style={{ fontSize: 12, color: me.has_pin ? "var(--accent-2)" : "var(--muted)" }}>
                {me.has_pin ? "🔒 Recovery PIN set" : "No recovery PIN — set one to protect access"}
              </span>
            </div>
          </div>
          <div className="row gap-2 wrap-flex">
            {window.RenameButton && <window.RenameButton leagueId={league.id} memberId={me.id} currentName={me.name} />}
            {window.SetPinButton && <window.SetPinButton leagueId={league.id} memberId={me.id} hasPin={me.has_pin} />}
          </div>
        </div>
      )}

      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill,minmax(300px,1fr))", gap: 18 }}>
        {rows.map((r) => (
          <TeamRosterCard key={r.m.id} row={r} draftPosition={draftPositionById[r.m.id]} />
        ))}
      </div>
      <p className="kicker" style={{ textAlign: "center", marginTop: 24, color: "var(--faint)" }}>
        {managers.length} managers · {league.roster_size} per roster
      </p>
    </div>
  );
}

// Used by Teams (rendered above) — registered on window for use after definition.
// Note: AccountRow etc. live in app.jsx; this scroll-on-hash handler is co-located
// with Teams here so it can read rows.length.

/* ============== ALL PLAYERS ============== */

function AllPlayers({ leagueState, players }) {
  const f = useFilters();
  const { managers, picks } = leagueState;
  const mById = React.useMemo(() => Object.fromEntries(managers.map(m => [m.id, m])), [managers]);
  const countries = React.useMemo(() => [...new Set(players.map((p) => p.country))].sort(), [players]);
  const filtered = applyFilters(players, f);

  // Sort state: null dir means "default order" (whatever the server returned, which is Pts desc).
  const [sort, setSort] = React.useState({ key: "pts", dir: "desc" });
  const cycleSort = (key) => setSort((prev) => {
    if (prev.key !== key) return { key, dir: "desc" };
    if (prev.dir === "desc") return { key, dir: "asc" };
    return { key: "pts", dir: "desc" }; // 3rd click → default
  });
  const sorted = React.useMemo(() => {
    if (sort.key === "pts" && sort.dir === "desc") return filtered;   // server default
    const dir = sort.dir === "asc" ? 1 : -1;
    return [...filtered].sort((x, y) => (x[sort.key] - y[sort.key]) * dir);
  }, [filtered, sort.key, sort.dir]);

  const SortableTh = ({ k, label, className, title }) => {
    const active = sort.key === k;
    const arrow = active ? (sort.dir === "asc" ? " ↑" : " ↓") : "";
    return (
      <th
        className={className}
        title={title || ""}
        onClick={() => cycleSort(k)}
        style={{ cursor: "pointer", userSelect: "none", color: active ? "var(--text)" : undefined }}
      >
        {label}{arrow}
      </th>
    );
  };

  return (
    <div className="wrap" style={{ paddingTop: 30, paddingBottom: 92 }}>
      <SectionTitle title="All players" />
      <FilterBar f={f} showAvail={picks.length > 0} countries={countries} />
      <div className="card" style={{ overflow: "hidden" }}>
        <table className="tbl">
          <thead><tr>
            <th>Player</th>
            <th className="hide-sm">Pos</th>
            <th>Nation</th>
            <th className="hide-sm">Club</th>
            <SortableTh k="g" label="G" className="center" />
            <SortableTh k="a" label="A" className="center" />
            <SortableTh k="gwg" label="GWG" className="center" title="Game-winning goals · +1 each" />
            <SortableTh k="pts" label="Pts" className="right" />
            <th className="hide-sm">Drafted by</th>
          </tr></thead>
          <tbody>
            {sorted.slice(0, 400).map((p) => {
              const takenBy = p.drafted_by ? mById[p.drafted_by] : null;
              return (
                <tr key={p.id}>
                  <td><div className="row gap-3"><PlayerAvatar player={p} size={32} /><b style={{ whiteSpace: "nowrap" }}>{p.name}</b></div></td>
                  <td className="hide-sm"><PosPill pos={p.pos} /></td>
                  <td><span style={{ fontSize: 14 }}><Flag country={p.country} size={15} /> {p.code}</span></td>
                  <td className="hide-sm" style={{ color: "var(--muted)", fontSize: 14 }}>{p.club}</td>
                  <td className="center num">{p.g}</td>
                  <td className="center num">{p.a}</td>
                  <td className="center num" style={{ color: p.gwg ? "var(--accent-2)" : "var(--faint)" }}>{p.gwg}</td>
                  <td className="right num" style={{ color: "var(--accent-2)", fontWeight: 700 }}>{p.pts.toFixed(1)}</td>
                  <td className="hide-sm">{takenBy ? <span className="chip" style={{ borderColor: takenBy.color }}><span className="dot" style={{ background: takenBy.color }}></span>{takenBy.name}</span> : (p.drafted_by_name ? <span style={{ color: "var(--muted)", fontSize: 14 }}>{p.drafted_by_name}</span> : <span style={{ color: "var(--faint)" }}>—</span>)}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
      {sorted.length > 400 && (
        <p style={{ color: "var(--muted)", fontSize: 14, marginTop: 20, textAlign: "center" }}>
          Showing top 400 of {sorted.length}. Narrow with filters.
        </p>
      )}
    </div>
  );
}

Object.assign(window, { Draft, Leaderboard, Teams, AllPlayers });
