<script lang="ts">
  import { onMount } from 'svelte';
  import MapCard from '$lib/components/MapCard.svelte';
  import PlayerCompareForm from '$lib/components/PlayerCompareForm.svelte';
  import HasToolAccess from '$lib/components/HasToolAccess.svelte';
  import {
    type MapMeta,
    type StarInfo,
    type BeatLeaderScore,
    type BeatLeaderScoresResponse,
    loadMetaForHashes,
    loadStarsForHashes,
    normalizeDifficultyName,
    parseTimeset,
    getCutoffEpochFromMonths,
    normalizeAccuracy,
    buildLatestByKey,
    fetchAllRecentScoresForDiff,
    fetchAllRecentScoresAllDiffs,
    mean,
    median,
    percentile,
    DIFFICULTIES,
    MODES,
    ONE_YEAR_SECONDS,
    TOOL_REQUIREMENTS,
    type BeatLeaderPlayerProfile
  } from '$lib/utils/plebsaber-utils';

  type H2HItem = {
    hash: string;
    diffName: string;
    modeName: string;
    timeset: number; // most recent between the two
    accA: number | null;
    accB: number | null;
    rankA?: number;
    rankB?: number;
    leaderboardId?: string;
  };

  export let data: { player: BeatLeaderPlayerProfile | null; adminRank: number | null; adminPlayer: BeatLeaderPlayerProfile | null };

  const requirement = TOOL_REQUIREMENTS['player-headtohead'];

  $: playerProfile = data?.player ?? null;
  $: adminRank = data?.adminRank ?? null;
  $: adminPlayer = data?.adminPlayer ?? null;

  let playerA = '';
  let playerB = '';
  const months = 24;

  // UI state
  let loading = false;
  let errorMsg: string | null = null;

  // Results state
  let items: H2HItem[] = [];
  let sortDir: 'asc' | 'desc' = 'desc';
  let page = 1;
  let pageSize: number | string = 24;
  let filterWinMargin: string = 'all'; // 'all', 'a1', 'a2', 'b1', 'b2'
  $: pageSizeNum = Number(pageSize) || 24;
  $: filtered = (() => {
    if (filterWinMargin === 'all') return items;
    if (filterWinMargin === 'a1') {
      return items.filter(i => {
        if (i.accA == null || i.accB == null) return false;
        return i.accA > i.accB && (i.accA - i.accB) > 1;
      });
    }
    if (filterWinMargin === 'a2') {
      return items.filter(i => {
        if (i.accA == null || i.accB == null) return false;
        return i.accA > i.accB && (i.accA - i.accB) > 2;
      });
    }
    if (filterWinMargin === 'b1') {
      return items.filter(i => {
        if (i.accA == null || i.accB == null) return false;
        return i.accB > i.accA && (i.accB - i.accA) > 1;
      });
    }
    if (filterWinMargin === 'b2') {
      return items.filter(i => {
        if (i.accA == null || i.accB == null) return false;
        return i.accB > i.accA && (i.accB - i.accA) > 2;
      });
    }
    return items;
  })();
  $: sorted = [...filtered].sort((a, b) => (sortDir === 'asc' ? a.timeset - b.timeset : b.timeset - a.timeset));
  $: totalPages = Math.max(1, Math.ceil(sorted.length / pageSizeNum));
  $: page = Math.min(page, totalPages);
  $: pageItems = sorted.slice((page - 1) * pageSizeNum, (page - 1) * pageSizeNum + pageSizeNum);

  // Metadata caches
  let metaByHash: Record<string, MapMeta> = {};
  let starsByKey: Record<string, StarInfo> = {};
  let loadingMeta = false;
  let loadingStars = false;

  // Lazy load metadata when pageItems changes
  $: if (pageItems.length > 0) {
    loadPageMetadata(pageItems);
  }

  async function loadPageMetadata(list: H2HItem[]): Promise<void> {
    const hashes = list.map(i => i.hash);
    
    // Load BeatSaver metadata
    loadingMeta = true;
    metaByHash = await loadMetaForHashes(hashes, metaByHash);
    loadingMeta = false;
    
    // Load star ratings
    loadingStars = true;
    starsByKey = await loadStarsForHashes(hashes, starsByKey, normalizeDifficultyName);
    loadingStars = false;
  }

  function toH2HItems(aMap: Map<string, BeatLeaderScore>, bMap: Map<string, BeatLeaderScore>): H2HItem[] {
    const out: H2HItem[] = [];
    for (const [key, aScore] of aMap) {
      if (!bMap.has(key)) continue;
      const bScore = bMap.get(key)!;
      const [hashLower, diffName, modeName] = key.split('|');
      const rawHash = (aScore.leaderboard?.song?.hash ?? bScore.leaderboard?.song?.hash ?? hashLower);
      const hash = String(rawHash).toLowerCase();
      const tA = parseTimeset(aScore.timeset);
      const tB = parseTimeset(bScore.timeset);
      const accA = normalizeAccuracy((aScore.accuracy ?? aScore.acc) as number | undefined);
      const accB = normalizeAccuracy((bScore.accuracy ?? bScore.acc) as number | undefined);
      const lbIdRaw = (aScore.leaderboard as any)?.id ?? (aScore.leaderboard as any)?.leaderboardId ?? (bScore.leaderboard as any)?.id ?? (bScore.leaderboard as any)?.leaderboardId;
      const leaderboardId = lbIdRaw != null ? String(lbIdRaw) : undefined;
      out.push({
        hash,
        diffName,
        modeName,
        timeset: Math.max(tA, tB),
        accA,
        accB,
        rankA: aScore.rank,
        rankB: bScore.rank,
        leaderboardId
      });
    }
    return out;
  }

  async function onCompare() {
    // Push current params into URL on user action
    updateUrl(false);
    errorMsg = null; items = []; metaByHash = {};
    const a = playerA.trim();
    const b = playerB.trim();
    if (!a || !b) { errorMsg = 'Please enter both Player A and Player B IDs.'; return; }
    loading = true;
    try {
      const cutoff = getCutoffEpochFromMonths(months);
      const [aScores, bScores] = await Promise.all([
        fetchAllRecentScoresAllDiffs(a, cutoff, normalizeDifficultyName, parseTimeset),
        fetchAllRecentScoresAllDiffs(b, cutoff, normalizeDifficultyName, parseTimeset)
      ]);
      const aLatest = buildLatestByKey(aScores, cutoff - ONE_YEAR_SECONDS, normalizeDifficultyName, parseTimeset);
      const bLatest = buildLatestByKey(bScores, cutoff - ONE_YEAR_SECONDS, normalizeDifficultyName, parseTimeset);
      const combined = toH2HItems(aLatest, bLatest);
      combined.sort((x, y) => y.timeset - x.timeset);
      items = combined;
      page = 1;
      // Metadata will be loaded lazily via reactive statement when pageItems changes
    } catch (err) {
      errorMsg = err instanceof Error ? err.message : 'Unknown error';
    } finally {
      loading = false;
    }
  }

  onMount(() => {
    const sp = new URLSearchParams(location.search);
    const p = sp.get('page');
    if (p) page = Math.max(1, Number(p) || 1);
    const dir = sp.get('dir');
    if (dir === 'asc' || dir === 'desc') sortDir = dir;
    const size = sp.get('size') ?? sp.get('ps');
    if (size) pageSize = Number(size) || pageSize;
    const filter = sp.get('filter');
    if (filter && ['all', 'a1', 'a2', 'b1', 'b2'].includes(filter)) filterWinMargin = filter;
    initialized = true;
  });

  // Short labels for players
  $: playerAId = playerA.trim();
  $: playerBId = playerB.trim();
  $: idShortA = playerAId ? playerAId.slice(0, 6) : 'A';
  $: idShortB = playerBId ? playerBId.slice(0, 6) : 'B';

  // URL param sync
  let initialized = false;
  let urlSyncInProgress = false;
  function updateUrl(replace = true) {
    if (!initialized || urlSyncInProgress) return;
    try {
      urlSyncInProgress = true;
      const sp = new URLSearchParams(location.search);
      // playerA and playerB are now handled by PlayerCompareForm component
      sp.delete('diff');
      sp.delete('mode');
      sp.delete('months');
      if (page > 1) sp.set('page', String(page)); else sp.delete('page');
      if (sortDir !== 'desc') sp.set('dir', sortDir); else sp.delete('dir');
      if (pageSizeNum !== 24) sp.set('size', String(pageSizeNum)); else sp.delete('size');
      if (filterWinMargin !== 'all') sp.set('filter', filterWinMargin); else sp.delete('filter');
      const qs = sp.toString();
      const url = location.pathname + (qs ? `?${qs}` : '');
      if (replace) history.replaceState(null, '', url); else history.pushState(null, '', url);
    } finally {
      urlSyncInProgress = false;
    }
  }

  // Sync URL on state changes
  $: updateUrl(true);

  // ===== Derived Stats for Visualizations =====
  $: comparable = items.filter((i) => i.accA != null && i.accB != null) as Array<{
    hash: string; diffName: string; modeName: string; timeset: number; accA: number; accB: number; rankA?: number; rankB?: number; leaderboardId?: string;
  }>;
  $: totalComparable = comparable.length;
  $: winsA = comparable.filter((i) => i.accA > i.accB).length;
  $: winsB = comparable.filter((i) => i.accB > i.accA).length;
  $: ties = comparable.filter((i) => i.accA === i.accB).length;

  $: accAList = comparable.map((i) => i.accA);
  $: accBList = comparable.map((i) => i.accB);
  $: avgAccA = mean(accAList);
  $: avgAccB = mean(accBList);
  $: medAccA = median(accAList);
  $: medAccB = median(accBList);

  $: deltas = comparable.map((i) => i.accA - i.accB);
  $: absMargins = deltas.map((x) => Math.abs(x));
  $: avgMargin = mean(absMargins);
  $: p95Margin = percentile(absMargins, 95);

  $: chronological = [...comparable].sort((a, b) => a.timeset - b.timeset);
  $: longestA = (() => {
    let cur = 0, best = 0;
    for (const i of chronological) {
      if (i.accA > i.accB) { cur += 1; best = Math.max(best, cur); } else if (i.accA === i.accB) { cur = 0; } else { cur = 0; }
    }
    return best;
  })();
  $: longestB = (() => {
    let cur = 0, best = 0;
    for (const i of chronological) {
      if (i.accB > i.accA) { cur += 1; best = Math.max(best, cur); } else if (i.accA === i.accB) { cur = 0; } else { cur = 0; }
    }
    return best;
  })();

  // Win share (bar + donut)
  $: shareA = totalComparable ? winsA / totalComparable : 0;
  $: shareT = totalComparable ? ties / totalComparable : 0;
  $: shareB = totalComparable ? winsB / totalComparable : 0;
  // Donut chart calculations
  const donutR = 44;
  $: donutCircumference = 2 * Math.PI * donutR;
  $: donutALen = donutCircumference * shareA;
  $: donutTLen = donutCircumference * shareT;
  $: donutBLen = donutCircumference * shareB;

  // Histogram of signed margins (A - B)
  $: maxAbsDelta = Math.max(0, ...deltas.map((x) => Math.abs(x)));
  $: histBins = 14;
  $: histRangeMin = -maxAbsDelta;
  $: histRangeMax = maxAbsDelta;
  $: histBinWidth = histBins ? (histRangeMax - histRangeMin) / histBins : 1;
  $: histogram = (() => {
    const bins = Array.from({ length: histBins }, () => 0);
    for (const x of deltas) {
      if (!Number.isFinite(x)) continue;
      let idx = Math.floor((x - histRangeMin) / histBinWidth);
      if (idx < 0) idx = 0; if (idx >= histBins) idx = histBins - 1;
      bins[idx] += 1;
    }
    return bins;
  })();
  $: histMaxCount = Math.max(1, ...histogram);

  // Cumulative wins over time sparkline
  $: cumSeries = (() => {
    const pts: { t: number; a: number; b: number }[] = [];
    let a = 0, b = 0;
    for (const i of chronological) {
      if (i.accA > i.accB) a += 1; else if (i.accB > i.accA) b += 1;
      pts.push({ t: i.timeset, a, b });
    }
    return pts;
  })();
  $: tMin = cumSeries.length ? cumSeries[0].t : 0;
  $: tMax = cumSeries.length ? cumSeries[cumSeries.length - 1].t : 1;
  function mapX(t: number, w: number): number {
    if (tMax === tMin) return 0;
    return ((t - tMin) / (tMax - tMin)) * w;
  }
  function mapY(v: number, h: number, vMax?: number): number {
    const maxV = vMax ?? Math.max(1, cumSeries.length ? Math.max(cumSeries[cumSeries.length - 1].a, cumSeries[cumSeries.length - 1].b) : 1);
    return h - (v / maxV) * h;
  }
</script>

<section class="py-8">
  <h1 class="font-display text-3xl sm:text-4xl">Player Head-to-Head</h1>
  <p class="mt-2 text-muted max-w-2xl">
    Compare two players on maps they've both played.
  </p>

  <HasToolAccess player={playerProfile} requirement={requirement} {adminRank} adminPlayer={adminPlayer}>
    <PlayerCompareForm bind:playerA bind:playerB {loading} hasResults={items.length > 0} oncompare={onCompare} currentPlayer={playerProfile} />

    {#if errorMsg}
      <div class="mt-4 text-danger">{errorMsg}</div>
    {/if}

    {#if items.length > 0}
      <!-- KPI Tiles -->
      <div class="mt-6 grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
        <div class="kpi-tile">
          <div class="kpi-label">Shared Maps</div>
          <div class="kpi-value">{totalComparable}</div>
        </div>
        <div class="kpi-tile a">
          <div class="kpi-label">Wins {idShortA}</div>
          <div class="kpi-value">{winsA}</div>
        </div>
        <div class="kpi-tile b">
          <div class="kpi-label">Wins {idShortB}</div>
          <div class="kpi-value">{winsB}</div>
        </div>
        <div class="kpi-tile">
          <div class="kpi-label">Ties</div>
          <div class="kpi-value">{ties}</div>
        </div>
      </div>
      <div class="mt-3 grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
        <div class="kpi-tile a">
          <div class="kpi-sublabel">Avg Acc {idShortA}</div>
          <div class="kpi-subvalue">{avgAccA.toFixed(2)}%</div>
        </div>
        <div class="kpi-tile b">
          <div class="kpi-sublabel">Avg Acc {idShortB}</div>
          <div class="kpi-subvalue">{avgAccB.toFixed(2)}%</div>
        </div>
        <div class="kpi-tile a">
          <div class="kpi-sublabel">Median {idShortA}</div>
          <div class="kpi-subvalue">{medAccA.toFixed(2)}%</div>
        </div>
        <div class="kpi-tile b">
          <div class="kpi-sublabel">Median {idShortB}</div>
          <div class="kpi-subvalue">{medAccB.toFixed(2)}%</div>
        </div>
      </div>
      <div class="mt-3 grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
        <div class="kpi-tile">
          <div class="kpi-sublabel">Avg Win Margin</div>
          <div class="kpi-subvalue">{avgMargin.toFixed(2)}%</div>
        </div>
        <div class="kpi-tile">
          <div class="kpi-sublabel">95th %ile Margin</div>
          <div class="kpi-subvalue">{p95Margin.toFixed(2)}%</div>
        </div>
        <div class="kpi-tile a">
          <div class="kpi-sublabel">Longest Streak {idShortA}</div>
          <div class="kpi-subvalue">{longestA}</div>
        </div>
        <div class="kpi-tile b">
          <div class="kpi-sublabel">Longest Streak {idShortB}</div>
          <div class="kpi-subvalue">{longestB}</div>
        </div>
      </div>

      <!-- Win Share: Bar + Donut -->
      <div class="mt-6 grid gap-4 lg:grid-cols-2">
        <div class="card-surface p-4">
          <div class="text-sm text-muted mb-2">Win Share</div>
          <div class="winshare-bar">
            <div class="seg a" style={`width: ${(shareA * 100).toFixed(2)}%`}></div>
            <div class="seg t" style={`width: ${(shareT * 100).toFixed(2)}%`}></div>
            <div class="seg b" style={`width: ${(shareB * 100).toFixed(2)}%`}></div>
          </div>
          <div class="mt-2 text-xs text-muted flex gap-3">
            <span class="badge a"></span> {idShortA} {(shareA * 100).toFixed(1)}%
            <span class="badge t"></span> Ties {(shareT * 100).toFixed(1)}%
            <span class="badge b"></span> {idShortB} {(shareB * 100).toFixed(1)}%
          </div>
        </div>
        <div class="card-surface p-4 flex items-center justify-center">
          <svg viewBox="0 0 120 120" width="160" height="160">
            <!-- Donut background -->
            <circle cx="60" cy="60" r="44" fill="none" stroke="rgba(255,255,255,0.08)" stroke-width="16" />
            {#if totalComparable > 0}
              <!-- A -->
              <circle cx="60" cy="60" r="44" fill="none" stroke="rgba(0,255,204,0.9)" stroke-width="16" stroke-dasharray={`${donutALen} ${donutCircumference - donutALen}`} stroke-dashoffset={0} />
              <!-- Ties -->
              <circle cx="60" cy="60" r="44" fill="none" stroke="rgba(200,200,200,0.7)" stroke-width="16" stroke-dasharray={`${donutTLen} ${donutCircumference - donutTLen}`} stroke-dashoffset={-donutALen} />
              <!-- B -->
              <circle cx="60" cy="60" r="44" fill="none" stroke="rgba(255,0,170,0.9)" stroke-width="16" stroke-dasharray={`${donutBLen} ${donutCircumference - donutBLen}`} stroke-dashoffset={-(donutALen + donutTLen)} />
            {/if}
            <text x="60" y="64" text-anchor="middle" font-size="14" fill="#9ca3af">{totalComparable} maps</text>
          </svg>
        </div>
      </div>

      <!-- Win Margin Histogram & Cumulative Wins -->
      <div class="mt-6 grid gap-4 lg:grid-cols-2">
        <div class="card-surface p-4">
          <div class="text-sm text-muted mb-2">Win Margin Histogram (A − B, %)</div>
          <div class="hist">
            {#each histogram as count, i}
              <div
                class="bar"
                title={`${(histRangeMin + (i + 0.5) * histBinWidth).toFixed(2)}%`}
                style={`left:${(i / histogram.length) * 100}%; width:${(1 / histogram.length) * 100}%; height:${((count / histMaxCount) * 100).toFixed(1)}%; background:${(histRangeMin + (i + 0.5) * histBinWidth) >= 0 ? 'rgba(0,255,204,0.8)' : 'rgba(255,0,170,0.8)'};`}
              ></div>
            {/each}
            <div class="zero-line"></div>
          </div>
          <div class="mt-2 text-xs text-muted">Left (magenta) favors {idShortB}, Right (cyan) favors {idShortA}</div>
        </div>
        <div class="card-surface p-4">
          <div class="text-sm text-muted mb-2">Cumulative Wins Over Time</div>
          <svg viewBox="0 0 600 140" class="spark">
            <!-- Axes bg -->
            <rect x="0" y="0" width="600" height="140" fill="transparent" />
            {#if cumSeries.length > 1}
              {#key cumSeries.length}
                <!-- A line -->
                <polyline fill="none" stroke="rgba(0,255,204,0.9)" stroke-width="2" points={cumSeries.map(p => `${mapX(p.t, 600)},${mapY(p.a, 120)}`).join(' ')} />
                <!-- B line -->
                <polyline fill="none" stroke="rgba(255,0,170,0.9)" stroke-width="2" points={cumSeries.map(p => `${mapX(p.t, 600)},${mapY(p.b, 120)}`).join(' ')} />
              {/key}
            {/if}
          </svg>
        </div>
      </div>
    {/if}

    {#if items.length > 0}
      <div class="mt-6 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
        <div class="text-sm text-muted">
          {filtered.length} / {items.length} songs
        </div>
        <div class="flex items-center gap-4 text-sm text-muted flex-wrap justify-end">
          <label class="flex items-center gap-3">
            <span class="filter-label {filterWinMargin !== 'all' ? 'active' : ''}">Options:</span>
            <select class="neon-select {filterWinMargin !== 'all' ? 'active' : ''}" bind:value={filterWinMargin}>
              <option value="all">All Songs</option>
              <option value="a1">{idShortA} wins by &gt;1%</option>
              <option value="a2">{idShortA} wins by &gt;2%</option>
              <option value="b1">{idShortB} wins by &gt;1%</option>
              <option value="b2">{idShortB} wins by &gt;2%</option>
            </select>
          </label>
          <label class="flex items-center gap-2">Dir
            <select class="neon-select" bind:value={sortDir}>
              <option value="desc">Desc</option>
              <option value="asc">Asc</option>
            </select>
          </label>
          <label class="flex items-center gap-2">Page size
            <select class="neon-select" bind:value={pageSize}>
              <option value={12}>12</option>
              <option value={24}>24</option>
              <option value={36}>36</option>
              <option value={48}>48</option>
            </select>
          </label>
        </div>
      </div>

      {#if loadingMeta}
        <div class="mt-2 text-xs text-muted">Loading covers…</div>
      {/if}
      {#if loadingStars}
        <div class="mt-2 text-xs text-muted">Loading star ratings…</div>
      {/if}

      <div class="mt-4 grid gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
        {#each pageItems as item}
          <article class="card-surface overflow-hidden">
            <MapCard
              hash={item.hash}
              coverURL={metaByHash[item.hash]?.coverURL}
              songName={metaByHash[item.hash]?.songName}
              mapper={metaByHash[item.hash]?.mapper}
              stars={starsByKey[`${item.hash}|${item.diffName}|${item.modeName}`]?.stars}
              timeset={item.timeset}
              diffName={item.diffName}
              modeName={item.modeName}
              leaderboardId={item.leaderboardId}
              beatsaverKey={metaByHash[item.hash]?.key}
            >
              <div slot="content">
                <div class="mt-3 grid grid-cols-2 gap-3 neon-surface">
                  <div class="player-card playerA {item.accA != null && item.accB != null && item.accA > item.accB ? 'winner' : ''}">
                    <div class="label {item.accA != null && item.accB != null && item.accA > item.accB ? 'winner-label' : ''}">{idShortA}</div>
                    <div class="value {item.accA != null && item.accB != null && item.accA > item.accB ? 'winner-value' : ''}">{item.accA != null ? item.accA.toFixed(2) + '%' : '—'}</div>
                    <div class="sub">{item.rankA ? `Rank #${item.rankA}` : ''}</div>
                  </div>
                  <div class="player-card playerB {item.accA != null && item.accB != null && item.accB > item.accA ? 'winner' : ''}">
                    <div class="label {item.accA != null && item.accB != null && item.accB > item.accA ? 'winner-label' : ''}">{idShortB}</div>
                    <div class="value {item.accA != null && item.accB != null && item.accB > item.accA ? 'winner-value' : ''}">{item.accB != null ? item.accB.toFixed(2) + '%' : '—'}</div>
                    <div class="sub">{item.rankB ? `Rank #${item.rankB}` : ''}</div>
                  </div>
                </div>
                <div class="mt-2 text-center text-sm">
                  {#if item.accA != null && item.accB != null}
                    {#if item.accA === item.accB}
                      <span class="chip chip-draw">TIE?!</span>
                    {:else if item.accA > item.accB}
                      <span class="chip chip-win-a">Winner: {idShortA}</span>
                      <span class="ml-2 text-muted margin-text {(item.accA - item.accB) > 1 ? 'margin-bold' : ''} {(item.accA - item.accB) > 2 ? 'margin-bright' : ''}">by {(item.accA - item.accB).toFixed(2)}%</span>
                    {:else}
                      <span class="chip chip-win-b">Winner: {idShortB}</span>
                      <span class="ml-2 text-muted margin-text {(item.accB - item.accA) > 1 ? 'margin-bold' : ''} {(item.accB - item.accA) > 2 ? 'margin-bright' : ''}">by {(item.accB - item.accA).toFixed(2)}%</span>
                    {/if}
                  {:else}
                    <span class="chip">Incomplete</span>
                  {/if}
                </div>
              </div>
            </MapCard>
          </article>
        {/each}
      </div>

      {#if totalPages > 1}
        <div class="mt-6 flex items-center justify-center gap-2">
          <button class="rounded-md border border-white/10 px-3 py-1 text-sm disabled:opacity-50" on:click={() => (page = Math.max(1, page - 1))} disabled={page === 1}>Prev</button>
          <span class="text-sm text-muted">Page {page} / {totalPages}</span>
          <button class="rounded-md border border-white/10 px-3 py-1 text-sm disabled:opacity-50" on:click={() => (page = Math.min(totalPages, page + 1))} disabled={page === totalPages}>Next</button>
        </div>
      {/if}
    {/if}
  </HasToolAccess>
</section>

<style>
  .text-danger { color: #dc2626; }

  /* Cyberpunk neon aesthetics */
  .neon-surface {
    padding: 16px;
    border-radius: 12px;
    background: radial-gradient(1200px 400px at -10% -10%, rgba(0, 255, 204, 0.08), transparent),
                radial-gradient(1200px 400px at 110% 110%, rgba(255, 0, 170, 0.08), transparent),
                rgba(12,12,18,0.6);
    border: 1px solid rgba(255,255,255,0.06);
    box-shadow: 0 0 20px rgba(0, 255, 204, 0.08), 0 0 30px rgba(255, 0, 170, 0.06) inset;
  }
  .player-card {
    padding: 16px;
    border-radius: 10px;
    background: linear-gradient(180deg, rgba(0,0,0,0.4), rgba(10,10,18,0.6));
    border: 1px solid rgba(255,255,255,0.06);
    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
  }
  .player-card.playerA { border-color: rgba(0, 255, 204, 0.25); box-shadow: 0 0 12px rgba(0, 255, 204, 0.08) inset; }
  .player-card.playerB { border-color: rgba(255, 0, 170, 0.5); box-shadow: 0 0 12px rgba(255, 0, 170, 0.15) inset; }
  .player-card:hover {
    transform: translateY(-2px);
  }
  .player-card .label { color: #9ca3af; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; transition: all 0.2s ease; }
  .player-card .label.winner-label { color: #ff8800; font-weight: 700; text-shadow: 0 0 8px rgba(255, 136, 0, 0.5); }
  .player-card .value { font-size: 26px; line-height: 1; font-weight: 800; letter-spacing: 0.02em; margin-top: 4px; white-space: nowrap; color: #9ca3af; transition: all 0.2s ease; }
  .player-card .value.winner-value { color: #ffffff; }
  .player-card .sub { margin-top: 6px; font-size: 12px; color: #9ca3af; }
  .player-card.playerA.winner {
    box-shadow: 0 0 0 1px rgba(0, 255, 204, 0.2) inset, 0 0 18px rgba(0, 255, 204, 0.14);
    border-color: rgba(0, 255, 204, 0.35);
  }
  .player-card.playerB.winner {
    box-shadow: 0 0 0 1px rgba(255, 0, 170, 0.3) inset, 0 0 18px rgba(255, 0, 170, 0.25);
    border-color: rgba(255, 0, 170, 0.7);
  }
  .chip {
    display: inline-block;
    border-radius: 9999px;
    border: 1px solid rgba(255,255,255,0.12);
    padding: 4px 10px;
    font-size: 12px;
    background: rgba(255,255,255,0.04);
  }
  .chip-win-a {
    border-color: rgba(0, 255, 204, 0.5);
    background: linear-gradient(90deg, rgba(0, 255, 204, 0.18), rgba(0, 255, 170, 0.10));
  }
  .chip-win-b {
    border-color: rgba(255, 0, 170, 0.5);
    background: linear-gradient(90deg, rgba(255, 0, 170, 0.18), rgba(255, 102, 204, 0.10));
  }
  .chip-draw {
    border-color: rgba(255, 255, 0, 0.5);
    background: linear-gradient(90deg, rgba(255, 255, 0, 0.14), rgba(255, 215, 0, 0.08));
  }

  /* Margin text styling */
  .margin-text.margin-bold { font-weight: 700; }
  .margin-text.margin-bright { color: #ffffff; }

  /* KPI tiles */
  .kpi-tile {
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 12px;
    padding: 12px 14px;
    background: linear-gradient(180deg, rgba(0,0,0,0.35), rgba(15,15,25,0.6));
  }
  .kpi-tile.a { box-shadow: 0 0 0 1px rgba(0,255,204,0.14) inset; }
  .kpi-tile.b { box-shadow: 0 0 0 1px rgba(255,0,170,0.14) inset; }
  .kpi-label { font-size: 12px; color: #9ca3af; letter-spacing: 0.06em; text-transform: uppercase; }
  .kpi-value { font-size: 28px; font-weight: 800; margin-top: 2px; }
  .kpi-sublabel { font-size: 11px; color: #9ca3af; }
  .kpi-subvalue { font-size: 20px; font-weight: 700; margin-top: 2px; }

  /* Win share bar */
  .winshare-bar {
    height: 16px;
    border-radius: 9999px;
    overflow: hidden;
    display: flex;
    background: rgba(255,255,255,0.08);
  }
  .winshare-bar .seg { height: 100%; }
  .winshare-bar .seg.a { background: rgba(0,255,204,0.9); }
  .winshare-bar .seg.t { background: rgba(200,200,200,0.7); }
  .winshare-bar .seg.b { background: rgba(255,0,170,0.9); }
  .badge { display: inline-block; width: 10px; height: 10px; border-radius: 9999px; margin-right: 6px; }
  .badge.a { background: rgba(0,255,204,0.9); }
  .badge.t { background: rgba(200,200,200,0.7); }
  .badge.b { background: rgba(255,0,170,0.9); }

  /* Histogram */
  .hist { position: relative; height: 120px; width: 100%; background: linear-gradient(180deg, rgba(255,255,255,0.04), transparent); border: 1px solid rgba(255,255,255,0.06); border-radius: 10px; }
  .hist .bar { position: absolute; bottom: 0; }
  .hist .zero-line { position: absolute; left: 50%; top: 0; bottom: 0; width: 1px; background: rgba(255,255,255,0.15); }

  /* Sparkline */
  .spark { width: 100%; height: 140px; }

  /* Filter label styling */
  .filter-label {
    font-size: 1em;
    letter-spacing: 0.05em;
    font-weight: 700;
    color: rgba(255, 0, 170, 0.95);
    text-shadow: 0 0 8px rgba(255, 0, 170, 0.3);
    transition: all 0.3s ease;
    display: inline-flex;
    align-items: center;
    font-family: var(--font-display);
    line-height: 1;
  }
  .filter-label.active {
    color: rgba(255, 0, 170, 1);
    text-shadow: 0 0 12px rgba(255, 0, 170, 0.5);
  }

  /* Neon select dropdown */
  .neon-select {
    border-radius: 0.375rem;
    border: 1px solid rgba(34, 211, 238, 0.3);
    background: linear-gradient(180deg, rgba(15,23,42,0.9), rgba(11,15,23,0.95));
    padding: 0.25rem 0.5rem;
    font-size: 0.875rem;
    color: rgba(148, 163, 184, 1);
    transition: all 0.2s ease;
    box-shadow: 0 0 8px rgba(34, 211, 238, 0.15);
    cursor: pointer;
  }
  .neon-select.active {
    border-color: rgba(34, 211, 238, 0.6);
    color: rgba(255, 255, 255, 1);
    box-shadow: 0 0 18px rgba(34, 211, 238, 0.35);
  }
  .neon-select:hover {
    border-color: rgba(34, 211, 238, 0.5);
    color: rgba(255, 255, 255, 0.9);
    box-shadow: 0 0 16px rgba(34, 211, 238, 0.25);
  }
  .neon-select:focus {
    outline: none;
    border-color: rgba(34, 211, 238, 0.7);
    box-shadow: 0 0 20px rgba(34, 211, 238, 0.35), 0 0 0 2px rgba(34, 211, 238, 0.1);
  }
  .neon-select option {
    background: #0f172a;
    color: #fff;
  }
</style>


