// Import af React fjernet, da React forventes at blive leveret som
// global variabel gennem <script>‑tags på PHP‑siden (React og
// ReactDOM fra CDN).  Når denne fil leveres med type="text/babel",
// vil Babel automatisk transformere JSX med global React.
/* global React */

/**
 * GatherArena · FACEIT Cups (Gaming Theme)
 * -------------------------------------------------------------
 * Self‑contained React/TSX: tema, helpers, data-hook, kort (future/history),
 * detaljeside med custom bracket-renderer + Twitch-sektion under Cup History.
 *
 * Denne version:
 * - Fikser JSX-syntaxfejl og uafsluttet komponent.
 * - Sorterer kommende cups med TIDLIGSTE først og fremhæver den som "featured".
 * - Resten af kommende cups vises kompakt.
 * - Korrekt FACEIT-links (uden {lang}).
 */

// ==========================
// Konstanter & Tema
// ==========================
// Basal konfiguration. ORGANIZER_ID angiver hvilken Faceit‑organisator vi henter cups fra.
// API‑nøglen opbevares ikke i denne klientkode; den ligger i faceit_proxy.php på serveren.
const ORGANIZER_ID = "bb21b455-936b-482a-a70c-5b265eeaafbf";
const TZ = "Europe/Copenhagen";

// Gaming-tema: mørk + orange accenter
const theme = {
  bgRoot:
    "min-h-screen p-6 space-y-4 text-orange-400 bg-gradient-to-b from-black via-gray-900 to-black bg-fixed",
  grid:
    "bg-[linear-gradient(rgba(255,255,255,0.04)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.04)_1px,transparent_1px)] bg-[size:24px_24px]",
  card:
    "bg-gray-900/80 border border-orange-700/40 rounded-2xl backdrop-blur-sm shadow-[0_0_30px_rgba(255,115,0,0.08)]",
  cardHover:
    "transition-transform duration-200 hover:-translate-y-0.5 hover:shadow-[0_0_24px_rgba(255,115,0,0.25)] hover:border-orange-500/60",
  textSoft: "text-orange-300",
  textSofter: "text-orange-200",
  textStrong: "text-orange-100",
  link: "underline text-orange-400 hover:text-orange-300",
  btn: "px-3 py-1 rounded bg-orange-500 text-black hover:bg-orange-400 transition-colors",
  hr: "h-1 w-20 bg-gradient-to-r from-orange-600 to-orange-300 rounded-full opacity-80",
  h1: "text-2xl font-extrabold tracking-wider text-transparent bg-clip-text bg-gradient-to-r from-orange-300 via-orange-500 to-orange-200",
  topbar: "sticky top-0 z-10 backdrop-blur bg-black/60 border-b border-orange-700/40",
};

// ==========================
// Hjælpefunktioner
// ==========================
function fmt(ts?: number | null) {
  if (ts === null || ts === undefined) return "—";
  const n = Number(ts);
  if (!Number.isFinite(n)) return "—";
  const epochSec = n > 1e12 ? Math.floor(n / 1000) : n; // ms vs s
  return new Date(epochSec * 1000).toLocaleString("da-DK", { timeZone: TZ });
}
function toMs(x: any): number | null {
  if (x === null || x === undefined) return null;
  const n = Number(x);
  if (!Number.isFinite(n)) return null;
  return n > 1e12 ? n : n > 1e9 ? n * 1000 : n;
}
function buildChampUrl(id: string, name?: string) {
  return `https://www.faceit.com/en/championship/${id}/${encodeURIComponent(name || "")}`;
}
function buildBracketUrl(id: string, name?: string) {
  return `${buildChampUrl(id, name)}/standings/column`;
}
function deriveCounts(c: any): { cur: number | null; max: number | null } {
  const pick = (arr: any[]) => { for (const v of arr) if (v !== undefined && v !== null) return Number(v); return null; };
  const cur = pick([c?.subscriptions_count,c?.registered_subscriptions,c?.participants_registered,c?.registered,c?.teams_registered,c?.players_registered,c?.join_count,c?.participants?.registered,c?.subscription_count,c?.num_participants,c?.participants_count]);
  const max = pick([c?.max_subscriptions,c?.participants_max,c?.max_participants,c?.slots,c?.teams_max,c?.participants?.max,c?.max_slots]);
  return { cur, max };
}
/**
 * Global helper that proxies requests through faceit_proxy.php on the server. This avoids
 * exposing the API key to the client and bypasses CORS restrictions. The path should
 * start with a leading slash (e.g. "/organizers/{id}/championships"). Additional
 * parameters (limit, offset, etc.) are forwarded as query parameters.
 */
async function fx(path: string, params?: Record<string, string | number | undefined>) {
  // Ensure path begins with a slash
  const normalizedPath = path.startsWith('/') ? path : '/' + path;
  const url = new URL('/faceit_proxy.php', window.location.origin);
  url.searchParams.set('path', normalizedPath);
  if (params) {
    Object.entries(params).forEach(([k, v]) => {
      if (v !== undefined) url.searchParams.set(k, String(v));
    });
  }
  const res = await fetch(url.toString());
  // Attempt to parse JSON; if parsing fails, return raw text
  const text = await res.text();
  try {
    const data = JSON.parse(text);
    return { ok: res.ok, status: res.status, data } as const;
  } catch {
    return { ok: res.ok, status: res.status, raw: text } as const;
  }
}

// ==========================
// UI småkomponenter
// ==========================
function Section({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <section className={`${theme.card} p-4`}>
      <div className="flex items-center justify-between mb-3">
        <h2 className={`font-semibold text-lg ${theme.h1}`}>{title}</h2>
        <div className={theme.hr} />
      </div>
      {children}
    </section>
  );
}
function TopBar({ title, onReload }: { title: string; onReload?: () => void }) {
  return (
    <div className={`${theme.topbar} mb-4`}>
      <div className="max-w-screen-xl mx-auto px-2 py-3 flex items-center gap-3">
        {/* Billedstien er relativ, da alle filer ligger i samme mappe på serveren */}
        <img src="OneDayCup-02-200x200.png" alt="Cup" className="w-8 h-8 rounded" />
        <div className={theme.h1}>{title}</div>
        <div className="ml-auto flex items-center gap-2 text-sm">
          {onReload && (<button className={theme.btn} onClick={onReload}>Genindlæs</button>)}
        </div>
      </div>
    </div>
  );
}

// ==========================
// Data-hook: useOrganizerChampionships (paged fetch)
// ==========================
function useOrganizerChampionships() {
  const [championshipItems, setChampionshipItems] = React.useState<any[]>([]);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [status, setStatus] = React.useState<{ championships?: number }>({});

  async function fetchPagedChampionships() {
    const limit = 100; let offset = 0; let all: any[] = [];
    while (true) {
      const page = await fx(`/organizers/${ORGANIZER_ID}/championships`, { limit, offset });
      if (typeof (page as any)?.status === "number") setStatus((s) => ({ ...s, championships: (page as any).status }));
      const items = (page as any)?.data?.items || [];
      all = all.concat(items);
      if (!items.length || items.length < limit) break;
      offset += limit;
    }
    return all;
  }

  const load = async () => {
    setLoading(true); setError(null);
    try { const ch = await fetchPagedChampionships(); setChampionshipItems(ch); }
    catch (e: any) { setError(e?.message || String(e)); }
    finally { setLoading(false); }
  };

  React.useEffect(() => { load(); }, []);

  return { status, championshipItems, loading, error, reload: load };
}

// ==========================
// Bracket helpers & komponenter
// ==========================
function takeTeamsPool(m: any): any[] | null {
  if (Array.isArray(m?.teams) && m.teams.length) return m.teams;
  if (Array.isArray(m?.factions) && m.factions.length) return m.factions;
  if (Array.isArray(m?.participants) && m.participants.length) return m.participants;
  return null;
}
const norm = (v: any): string | null => (v ? String(v).trim() : null);
function nameOf(x: any): string {
  return (
    norm(x?.team?.name) || norm(x?.team?.nickname) || norm(x?.team?.title) ||
    norm(x?.player?.nickname) || norm(x?.name) || norm(x?.team_name) ||
    norm(x?.nickname) || norm(x?.entity_name) || "TBD"
  )!;
}
function scoreOf(x: any): number { const s = x?.score ?? x?.result?.score ?? x?.stats?.score; return Number.isFinite(Number(s)) ? Number(s) : 0; }
function isWinner(x: any): boolean { const r = String(x?.result || x?.outcome || "").toLowerCase(); return x?.is_winner === true || x?.winner === true || r === "winner" || r === "win"; }
function roundIndex(m: any): number {
  const candidates = [m?.round, m?.round_number, m?.roundIndex, m?.match_round];
  for (const c of candidates) { const n = Number(c); if (Number.isFinite(n)) return n; }
  const name = String(m?.round_name || m?.stage || m?.phase || "").toLowerCase();
  if (name.includes("final") && !name.includes("semi")) return 99;
  if (name.includes("semi")) return 50;
  if (name.includes("quarter")) return 40;
  return 10;
}
function matchOrder(a: any, b: any) { const ka = a?.match_number ?? a?.number ?? a?.id ?? a?.created_at ?? 0; const kb = b?.match_number ?? b?.number ?? b?.id ?? b?.created_at ?? 0; return (Number(ka) || 0) - (Number(kb) || 0); }

function MatchCard({ m }: { m: any }) {
  const pool = takeTeamsPool(m) || []; const a = pool[0] || {}; const b = pool[1] || {};
  const an = nameOf(a), bn = nameOf(b); const as = scoreOf(a), bs = scoreOf(b);
  const aw = isWinner(a), bw = isWinner(b); const state = String(m?.state || m?.status || "").toLowerCase();
  const finished = state === "finished" || state === "closed" || state === "completed";
  return (
    <div className={`${theme.card} p-2 text-xs`}>
      <div className="flex items-center justify-between text-[10px] mb-1 opacity-80">
        <span>#{m?.match_number ?? m?.number ?? m?.id ?? ""}</span>
        <span className="uppercase">{finished ? "Færdig" : state || "Planlagt"}</span>
      </div>
      <div className={`flex items-center justify-between rounded px-2 py-1 mb-1 ${aw ? 'bg-orange-500 text-black' : 'bg-gray-800 text-orange-200'}`}>
        <span className="truncate mr-2">{an}</span><span className="font-bold">{as}</span>
      </div>
      <div className={`flex items-center justify-between rounded px-2 py-1 ${bw ? 'bg-orange-500 text-black' : 'bg-gray-800 text-orange-200'}`}>
        <span className="truncate mr-2">{bn}</span><span className="font-bold">{bs}</span>
      </div>
    </div>
  );
}

function BracketView({ champId }: { champId: string }) {
  const [byRound, setByRound] = React.useState<Record<number, any[]>>({});
  const [rounds, setRounds] = React.useState<number[]>([]);
  const [loading, setLoading] = React.useState(false);
  const [err, setErr] = React.useState<string | null>(null);

  React.useEffect(() => {
    let alive = true; const run = async () => {
      setLoading(true); setErr(null);
      try {
        const limit = 200; let offset = 0; const all: any[] = [];
        while (true) {
          const r = await fx(`/championships/${champId}/matches`, { limit, offset });
          const items = (r as any)?.data?.items ?? (r as any)?.data ?? [];
          all.push(...items); if (!items.length || items.length < limit) break; offset += limit;
        }
        const map: Record<number, any[]> = {};
        for (const m of all) { const ri = roundIndex(m); (map[ri] ||= []).push(m); }
        Object.values(map).forEach((list) => list.sort(matchOrder));
        const keys = Object.keys(map).map((n) => Number(n)).sort((a, b) => a - b);
        if (alive) { setByRound(map); setRounds(keys); }
      } catch (e: any) { if (alive) setErr(e?.message || String(e)); }
      finally { if (alive) setLoading(false); }
    }; run(); return () => { alive = false; };
  }, [champId]);

  if (loading && !rounds.length) return <div className={theme.textSofter}>Henter bracket…</div>;
  if (err) return <div className="text-red-400">{err}</div>;
  if (!rounds.length) return <div className={theme.textSofter}>Ingen bracket-data fundet.</div>;

  return (
    <div className="overflow-x-auto">
      <div className="min-w-[960px] grid gap-3" style={{ gridTemplateColumns: `repeat(${rounds.length}, minmax(220px, 1fr))` }}>
        {rounds.map((r) => (
          <div key={r} className="space-y-3">
            <div className={`text-sm font-semibold ${theme.textStrong}`}>Round {r === 99 ? 'Final' : r}</div>
            {byRound[r]?.map((m, idx) => (<MatchCard key={(m?.id ?? m?.match_id ?? idx) + '_' + r} m={m} />))}
          </div>
        ))}
      </div>
    </div>
  );
}

// ==========================
// Kort: Afsluttede (vinder + runner-up)
// ==========================
function FinishedChampionshipCard({ c, onDetail }: { c: any; onDetail?: () => void }) {
  const [winner, setWinner] = React.useState<string | null>(null);
  const [runnerUp, setRunnerUp] = React.useState<string | null>(null);
  const [loading, setLoading] = React.useState<boolean>(false);
  const [subsTotal, setSubsTotal] = React.useState<number | null>(null);

  function nameOfLocal(x: any): string | null {
    if (!x) return null;
    return (x?.team?.name ?? x?.team?.nickname ?? x?.team?.title ?? x?.player?.nickname ?? x?.name ?? x?.team_name ?? x?.nickname ?? x?.entity_name ?? null);
  }
  function extractTopTwo(list: any[]): { winner: string | null; runner: string | null } {
    let first: string | null = null, second: string | null = null;
    if (Array.isArray(list)) {
      const sorted = list.slice().sort((a: any, b: any) => {
        const ra = a?.rank ?? a?.placement ?? a?.position ?? a?.place ?? a?.final_rank ?? a?.final_position ?? 9999;
        const rb = b?.rank ?? b?.placement ?? b?.position ?? b?.place ?? b?.final_rank ?? b?.final_position ?? 9999;
        return (Number(ra) || 9999) - (Number(rb) || 9999);
      });
      if (sorted[0]) first = nameOfLocal(sorted[0]);
      if (sorted[1]) second = nameOfLocal(sorted[1]);
    }
    return { winner: first, runner: second };
  }
  async function getTopTwoFromResults(champId: string) { const res = await fx(`/championships/${champId}/results`); const arr = (res as any)?.data?.items ?? (res as any)?.data ?? []; return extractTopTwo(arr); }
  async function getTopTwoFromLeaderboards(champId: string) {
    const lbs = await fx(`/leaderboards/championships/${champId}`); const groups = (lbs as any)?.data?.items ?? (lbs as any)?.data ?? [];
    const g = Array.isArray(groups) && groups.length ? groups[0] : null; const groupId = g?.group_id ?? g?.group ?? g?.id ?? g?.slug ?? g?.uuid ?? null;
    if (!groupId) return { winner: null, runner: null };
    const grp = await fx(`/leaderboards/championships/${champId}/groups/${groupId}`); const rows = (grp as any)?.data?.items ?? (grp as any)?.data ?? [];
    return extractTopTwo(rows);
  }
  async function getTopTwoFromMatches(champId: string) {
    const m = await fx(`/championships/${champId}/matches`); const items = (m as any)?.data?.items ?? (m as any)?.data ?? [];
    if (!Array.isArray(items) || !items.length) return { winner: null, runner: null };
    const sorted = items.slice().sort((a: any, b: any) => (String(b?.state).toLowerCase() === 'finished' ? 1 : 0) - (String(a?.state).toLowerCase() === 'finished' ? 1 : 0) || (b?.round || 0) - (a?.round || 0));
    const final = sorted[0]; if (!final) return { winner: null, runner: null };
    const colls = [final.teams, final.factions, final.participants].filter((x: any) => Array.isArray(x));
    for (const col of colls) {
      const win = col.find((t: any) => t?.result === 'winner' || t?.is_winner === true || t?.winner === true || String(t?.outcome).toLowerCase() === 'win');
      if (win) { const w = nameOfLocal(win); const others = col.filter((t: any) => t !== win); const r = others.length ? nameOfLocal(others[0]) : null; return { winner: w, runner: r }; }
      if (col.length === 2) { const [a, b] = col; const sA = (a?.score ?? a?.result?.score ?? a?.stats?.score ?? 0) * 1; const sB = (b?.score ?? b?.result?.score ?? b?.stats?.score ?? 0) * 1; if (sA !== sB) return { winner: nameOfLocal(sA > sB ? a : b), runner: nameOfLocal(sA > sB ? b : a) }; }
    }
    return { winner: null, runner: null };
  }

  React.useEffect(() => { let alive = true; (async () => {
    try { const res = await fx(`/championships/${c?.championship_id}/subscriptions`, { limit: 1, offset: 0 });
      const total = (res as any)?.data?.total ?? (res as any)?.data?.pagination?.total ?? (res as any)?.data?.total_items ?? null;
      if (alive) setSubsTotal(typeof total === 'number' ? total : null);
    } catch {} })(); return () => { alive = false; }; }, [c?.championship_id]);

  React.useEffect(() => { let mounted = true; (async () => {
    setLoading(true);
    try { const id = c?.championship_id; let top = await getTopTwoFromResults(id); if (!top.winner) top = await getTopTwoFromLeaderboards(id); if (!top.winner) top = await getTopTwoFromMatches(id); if (mounted) { setWinner(top.winner); setRunnerUp(top.runner); } }
    catch { if (mounted) { setWinner(null); setRunnerUp(null); } }
    finally { if (mounted) setLoading(false); }
  })(); return () => { mounted = false; }; }, [c?.championship_id]);

  const bracketUrl = buildBracketUrl(c.championship_id, c.name);
  const { cur, max } = deriveCounts(c); const curDisp = subsTotal !== null ? subsTotal : (cur !== null ? cur : 0); const maxDisp = max !== null ? max : (curDisp > 0 ? curDisp : 0);

  return (
    <div className={`${theme.card} ${theme.cardHover} p-3`}>
      <div className={`font-medium truncate ${theme.textStrong}`}>{c.name || c.championship_id}</div>
      <div className={`text-xs ${theme.textSofter}`}>Dato: {c.championship_end ? fmt(c.championship_end) : c.championship_start ? fmt(c.championship_start) : '—'}</div>
      <div className={`text-xs ${theme.textSofter}`}>Teams: {maxDisp}</div>
      <div className="text-xs mt-1">{loading ? (<span className={theme.textSofter}>Henter placeringer…</span>) : (<><div>Vinder: <span className="font-semibold text-orange-300">{winner || '—'}</span> · <a className={theme.link} href={bracketUrl} target="_blank" rel="noreferrer">Se brackets</a></div><div>Runner-up: <span className="font-semibold text-orange-300">{runnerUp || '—'}</span></div></>)}
      </div>
      <div className={`text-xs ${theme.textSofter}`}>Game: {c.game_id || c.game_data?.game_id || '—'} · Region: {c.region || '—'}</div>
      <div className="text-xs mt-1"><a href={buildChampUrl(c.championship_id, c.name)} className={theme.link} target="_blank" rel="noreferrer">Åbn i FACEIT</a></div>
      {onDetail && (<div className="mt-2"><button className={theme.btn} onClick={onDetail}>Detaljer</button></div>)}
    </div>
  );
}

// ==========================
// Kort: Kommende (Tilmeldte X/Y + lille countdown)
// ==========================
function UpcomingChampionshipCard({ c, onDetail, variant = 'featured' }: { c: any; onDetail?: () => void; variant?: 'featured' | 'compact' }) {
  const [subsTotal, setSubsTotal] = React.useState<number | null>(null);
  const [now, setNow] = React.useState<number>(() => Date.now());

  React.useEffect(() => { const t = setInterval(() => setNow(Date.now()), 1000); return () => clearInterval(t); }, []);

  React.useEffect(() => { let alive = true; (async () => {
    try { const res = await fx(`/championships/${c?.championship_id}/subscriptions`, { limit: 1, offset: 0 });
      const total = (res as any)?.data?.total ?? (res as any)?.data?.pagination?.total ?? (res as any)?.data?.total_items ?? null;
      if (alive) setSubsTotal(typeof total === 'number' ? total : null);
    } catch {} })(); return () => { alive = false; }; }, [c?.championship_id]);

  const { cur, max } = deriveCounts(c); const curDisp = subsTotal !== null ? subsTotal : (cur !== null ? cur : 0); const maxDisp = max !== null ? max : (curDisp > 0 ? curDisp : 0);

  const startMs = toMs(c?.championship_start); let countdown: string | null = null;
  if (startMs) { const diff = Math.max(0, startMs - now); const d = Math.floor(diff / (24 * 3600000)); const h = Math.floor((diff % (24 * 3600000)) / 3600000); const m = Math.floor((diff % 3600000) / 60000); const s = Math.floor((diff % 60000) / 1000); countdown = `${d}d ${h}t ${m}m ${s}s`; }

  const cardEmphasis = variant === 'featured' ? `${theme.card} ${theme.cardHover} p-4 ring-1 ring-orange-500/30` : `${theme.card} p-3 opacity-90`;

  return (
    <div className={cardEmphasis}>
      <div className={`truncate ${variant === 'featured' ? 'text-lg' : 'text-sm'} font-semibold ${theme.textStrong}`}>{c.name || c.championship_id}</div>
      <div className={`text-xs ${theme.textSofter}`}>Dato: {c.championship_start ? fmt(c.championship_start) : '—'}</div>
      {countdown && <div className={`${variant === 'featured' ? 'text-sm' : 'text-xs'} ${theme.textSoft}`}>Starter om: {countdown}</div>}
      <div className={`text-xs ${theme.textSofter}`}>Tilmeldte: {curDisp}/{maxDisp}</div>
      <div className={`text-[11px] ${theme.textSofter}`}>Game: {c.game_id || c.game_data?.game_id || '—'} · Region: {c.region || '—'}</div>
      <div className="mt-2 flex flex-wrap gap-2">
        {onDetail && (
          <button className={`${variant === 'featured' ? 'px-4 py-2' : 'px-3 py-1 text-xs'} rounded bg-gray-700 text-orange-200 font-medium hover:bg-gray-600 transition-colors`} onClick={onDetail}>Detaljer</button>
        )}
        <a href={buildChampUrl(c.championship_id, c.name)} className={`flex items-center gap-2 ${variant === 'featured' ? 'px-5 py-2 text-base' : 'px-3 py-1 text-xs'} rounded bg-gradient-to-r from-orange-500 to-red-500 text-black font-bold shadow-lg hover:from-orange-400 hover:to-red-400 transition-transform transform hover:scale-105`} target="_blank" rel="noreferrer">
          <img src="https://seeklogo.com/images/F/faceit-logo-861E1D6F8C-seeklogo.com.png" alt="Faceit" className={`${variant === 'featured' ? 'w-4 h-4' : 'w-3 h-3'}`} />
          Tilmeld dig her
        </a>
      </div>
    </div>
  );
}

// ==========================
// Detaljeside (custom bracket)
// ==========================
function ChampionshipDetail({ id, name, onBack }: { id: string; name?: string; onBack: () => void }) {
  const [det, setDet] = React.useState<any>(null);
  const [loading, setLoading] = React.useState<boolean>(false);
  const [err, setErr] = React.useState<string | null>(null);

  React.useEffect(() => { (async () => {
    setLoading(true); setErr(null);
    try { const d = await fx(`/championships/${id}`); setDet((d as any)?.data ?? null); }
    catch (e: any) { setErr(e?.message || String(e)); }
    finally { setLoading(false); }
  })(); }, [id]);

  const bracketUrl = buildBracketUrl(id, name || det?.name);

  return (
    <div className="space-y-4">
      <div className="flex items-center gap-2">
        <button className={theme.btn} onClick={onBack}>← Tilbage</button>
        <h2 className={`text-xl font-semibold ${theme.h1}`}>{det?.name || name || id}</h2>
      </div>
      {loading && <div className={theme.textSofter}>Indlæser detaljer…</div>}
      {err && <div className="text-red-400">{err}</div>}

      <div className={`${theme.card} p-4`}>
        <h3 className={`font-semibold mb-2 ${theme.textStrong}`}>Oversigt</h3>
        <div className={`text-sm ${theme.textSoft} space-y-1`}>
          <div>Game: {det?.game || det?.game_id || '—'}{det?.game_data?.game_id ? ` (${det?.game_data?.game_id})` : ''}</div>
          <div>Region: {det?.region || '—'}</div>
          <div>Start: {det?.championship_start ? fmt(det?.championship_start) : '—'}</div>
          <div>Slut: {det?.championship_end ? fmt(det?.championship_end) : '—'}</div>
          {(() => { const st = String(det?.status || '').toLowerCase(); return st !== 'cancelled' && st !== 'canceled' ? <div>Status: {det?.status || '—'}</div> : null; })()}
          <div>Brackets: <a className={theme.link} href={bracketUrl} target="_blank" rel="noreferrer">Åbn</a></div>
        </div>
      </div>

      <div className={`${theme.card} p-4`}>
        <div className="flex items-center justify-between mb-2">
          <h3 className={`font-semibold ${theme.textStrong}`}>Brackets</h3>
          <a className={theme.link} href={bracketUrl} target="_blank" rel="noreferrer">Åbn på FACEIT</a>
        </div>
        <BracketView champId={id} />
      </div>
    </div>
  );
}

// ==========================
// Twitch-sektion under Cup History (countdown + stream i én boks)
// ==========================
function useCountdown(targetMs: number | null) {
  const [now, setNow] = React.useState<number>(() => Date.now());
  React.useEffect(() => { const t = setInterval(() => setNow(Date.now()), 1000); return () => clearInterval(t); }, []);
  if (targetMs === null) return { d: 0, h: 0, m: 0, s: 0 };
  const diff = Math.max(0, targetMs - now);
  const d = Math.floor(diff / (24 * 3600000));
  const h = Math.floor((diff % (24 * 3600000)) / 3600000);
  const m = Math.floor((diff % 3600000) / 60000);
  const s = Math.floor((diff % 60000) / 1000);
  return { d, h, m, s };
}
function TwitchUnderHistory({ future, channelHint }: { future: any[]; channelHint?: string }) {
  const nextCup = React.useMemo(() => {
    if (!future || !future.length) return null;
    const sortedAsc = future.slice().sort((a: any, b: any) => (toMs(a?.championship_start) || 0) - (toMs(b?.championship_start) || 0));
    return sortedAsc[0] || null;
  }, [future]);

  const nextStart = nextCup ? toMs(nextCup?.championship_start) : null; const { d, h, m, s } = useCountdown(nextStart);
  const now = Date.now(); const live = nextStart !== null && now >= nextStart - 5 * 60000 && now <= nextStart + 4 * 3600000;
  const channel = channelHint || 'onedaycup';
  const parent = typeof window !== 'undefined' && window.location && window.location.hostname ? window.location.hostname : 'localhost';
  const twitchUrl = `https://www.twitch.tv/${channel}`;

  return (
    <section className={`${theme.card} p-4 mt-2`}>
      <div className="flex items-center justify-between mb-3">
        <h2 className={`font-semibold text-lg ${theme.h1}`}>Twitch · Live & Countdown</h2>
        <div className={theme.hr} />
      </div>
      <div className="flex flex-wrap items-center gap-3 mb-3">
        <div className={"inline-flex items-center gap-2 px-2 py-0.5 rounded-full text-xs font-semibold shadow " + (live ? 'bg-red-600 text-white shadow-red-400/40' : 'bg-gray-800 text-orange-300 border border-orange-700/50')}>
          <span className={`inline-block w-2 h-2 rounded-full ${live ? 'bg-white animate-pulse' : 'bg-orange-400'}`}></span>
          {live ? 'LIVE nu på Twitch' : 'Venter på næste cup'}
        </div>
        <div className="text-sm text-orange-200">Næste cup: <span className="font-extrabold text-orange-100">{nextStart ? `${d}d ${h}t ${m}m ${s}s` : '—'}</span><span className="ml-2 text-xs text-orange-300">{nextStart ? fmt(nextStart) : 'Ingen kommende cups fundet'}</span></div>
      </div>
      <div className="rounded-2xl overflow-hidden border border-orange-700/40 bg-black">
        <iframe title="Twitch Player" src={`https://player.twitch.tv/?channel=${encodeURIComponent(channel)}&parent=${encodeURIComponent(parent)}&muted=${live ? 'false' : 'true'}&autoplay=${live ? 'true' : 'false'}`} height="420" className="w-full" allowFullScreen sandbox="allow-same-origin allow-scripts allow-popups allow-forms" />
      </div>
      <div className="mt-3 flex items-center gap-3">
        <a className={theme.btn} href={twitchUrl} target="_blank" rel="noreferrer">Åbn Twitch</a>
        {nextCup?.name && <span className="text-xs text-orange-300">Næste: {nextCup.name}</span>}
      </div>
    </section>
  );
}

// ==========================
// Root App
// ==========================
// Root React component. We avoid using ES module exports here because the
// script is loaded directly in the browser (type="text/babel"), and we
// need `App` to be available in the global scope for ReactDOM.render.
function App() {
  const { championshipItems, loading, error, reload } = useOrganizerChampionships();
  const [view, setView] = React.useState<{ id: string; name?: string } | null>(null);

  const nowMs = Date.now();
  const championshipFuture = React.useMemo(
    () => (championshipItems || [])
      .filter((c: any) => {
        const startMs = toMs(c?.championship_start);
        const st = String(c?.status || '').toLowerCase();
        return startMs !== null && st !== 'finished' && st !== 'cancelled' && st !== 'canceled';
      })
      // stigning: tidligst først
      .sort((a: any, b: any) => (toMs(a?.championship_start) || 0) - (toMs(b?.championship_start) || 0))
  , [championshipItems]);

  const championshipFinished = React.useMemo(
    () => (championshipItems || [])
      .map((c: any) => { const endMs = toMs(c?.championship_end); const startMs = toMs(c?.championship_start); const sortMs = endMs !== null ? endMs : startMs !== null ? startMs : 0; return { ...c, __sortMs: sortMs }; })
      .filter((c: any) => { const endMs = toMs(c?.championship_end); const st = String(c?.status || '').toLowerCase(); return st !== 'cancelled' && st !== 'canceled' && (st === 'finished' || (endMs !== null ? endMs < nowMs : (c.__sortMs ?? 0) < nowMs)); })
      .sort((a: any, b: any) => (b.__sortMs ?? 0) - (a.__sortMs ?? 0))
  , [championshipItems]);

  if (view) {
    return (
      <div className={`${theme.bgRoot} ${theme.grid}`}>
        <TopBar title={view.name || 'Championship'} onReload={reload} />
        <ChampionshipDetail id={view.id} name={view.name} onBack={() => setView(null)} />
      </div>
    );
  }

  return (
    <div className={`${theme.bgRoot} ${theme.grid}`}>
      <TopBar title="GatherArena - Klar til at clutche" onReload={reload} />

      {loading && <div className={theme.textSofter}>Indlæser…</div>}
      {error && <div className="text-red-400">{error}</div>}

      <Section title={`Ready for Battle – Future Clutches ( ${championshipFuture.length} )`}>
        {championshipFuture.length ? (
          <div id="future" className="grid sm:grid-cols-2 lg:grid-cols-3 gap-3">
            {/* FEATURED: tidligst start som første og større */}
            {championshipFuture[0] && (
              <div className="sm:col-span-2 lg:col-span-2">
                <UpcomingChampionshipCard
                  c={championshipFuture[0]}
                  variant="featured"
                  onDetail={() => setView({ id: championshipFuture[0].championship_id, name: championshipFuture[0].name })}
                />
              </div>
            )}
            {/* Øvrige kompakt */}
            {championshipFuture.slice(1).map((c: any) => (
              <div key={c.championship_id} className="opacity-90">
                <UpcomingChampionshipCard c={c} variant="compact" onDetail={() => setView({ id: c.championship_id, name: c.name })} />
              </div>
            ))}
          </div>
        ) : (
          <div className={theme.textSofter}>Ingen kommende championships fundet.</div>
        )}
      </Section>

      <Section title={`Wall of Fame – Cup History ( ${championshipFinished.length} )`}>
        {championshipFinished.length ? (
          <div id="history" className="grid sm:grid-cols-2 lg:grid-cols-3 gap-3">
            {championshipFinished.map((c: any) => (
              <FinishedChampionshipCard key={c.championship_id} c={c} onDetail={() => setView({ id: c.championship_id, name: c.name })} />
            ))}
          </div>
        ) : (
          <div className={theme.textSofter}>Ingen afsluttede championships fundet.</div>
        )}
      </Section>

      <TwitchUnderHistory future={championshipFuture} channelHint={'onedaycup'} />
    </div>
  );
}

// ==========================
// Små sanity-tests (ikke-invasive)
// ==========================
(function __sanity() {
  try {
    console.assert(typeof fmt === 'function', 'fmt findes');
    console.assert(toMs(1765648800) === 1765648800000, 'toMs s→ms');
    console.assert(toMs(1765648800000) === 1765648800000, 'toMs ms passthrough');
    console.assert(deriveCounts({ subscriptions_count: 0 }).cur === 0, '0 bevares');
    const arr = [{ __sortMs: 1 }, { __sortMs: 3 }, { __sortMs: 2 }].sort((a: any, b: any) => (b.__sortMs ?? 0) - (a.__sortMs ?? 0));
    console.assert(arr[0].__sortMs === 3 && arr[2].__sortMs === 1, 'desc sort ok');
    console.assert(roundIndex({ round: 2 }) === 2, 'round numeric');
    console.assert(roundIndex({ round_name: 'Grand Final' }) === 99, 'round final');
    console.assert(Array.isArray(takeTeamsPool({ teams: [1] })), 'teams pool');
  } catch (_) { /* no-op */ }
})();
