/* global React, useApi, useMeta, useAuth, Loading, ApiError, Tag, MDot, ModelAccuracyChart, AccuracyLineChart, formatMoney */

// =========================================================================
// LEADERBOARD — official (all enabled models) + community (user-tracked prompts).
// =========================================================================
function LeaderboardPage({ navigate }) {
  const { categories, models } = useMeta();
  const modelCount = models?.length || 0;
  const [tab, setTab] = React.useState('official');
  const [cat, setCat] = React.useState('all');
  const [tw, setTw]   = React.useState('30d');
  // Which model row is expanded to show per-category breakdown.
  const [expanded, setExpanded] = React.useState(null);

  const official = useApi(
    () => window.CloudLayerAPI.leaderboardOfficial({
      category: cat === 'all' ? '' : cat,
      window: tw === 'all' ? '' : tw,
    }),
    [cat, tw],
  );
  const community = useApi(() => window.CloudLayerAPI.leaderboardCommunity({ limit: 100 }), []);
  const communityTimeseries = useApi(
    () => window.CloudLayerAPI.leaderboardCommunityTimeseries({ days: 30, limit: 8 }),
    [],
  );
  const cats      = useApi(() => window.CloudLayerAPI.listCategories(), []);
  // Map the window chip to a day count for the chart. "all" stretches a long
  // way back; 90d / 30d / 7d cap accordingly. The chart's auto-fit then
  // tightens around whatever data actually exists in that window.
  const timeseriesDays = tw === '7d' ? 7
                       : tw === '90d' ? 90
                       : tw === 'all' ? 180
                       : 30;
  const timeseries = useApi(
    () => window.CloudLayerAPI.leaderboardTimeseries({
      days: timeseriesDays,
      category: cat === 'all' ? '' : cat,
    }),
    [cat, tw],
  );
  const versions  = useApi(() => window.CloudLayerAPI.modelVersions(), []);

  React.useEffect(() => {
    const t = setInterval(() => {
      official.refresh(); community.refresh(); timeseries.refresh(); versions.refresh();
    }, 60_000);
    return () => clearInterval(t);
  }, [official.refresh, community.refresh, timeseries.refresh, versions.refresh]);

  // Collapse expanded row when filters change — the breakdown reflects the
  // current response, and stale data under a closed-then-reopened panel
  // would be misleading.
  React.useEffect(() => { setExpanded(null); }, [cat, tw, tab]);

  const totals = (cats.data?.items || []).reduce(
    (acc, c) => ({ markets: acc.markets + c.markets, volume: acc.volume + c.volume }),
    { markets: 0, volume: 0 },
  );

  return (
    <div data-screen-label="04 Leaderboard">
      <div className="page-head">
        <div className="container">
          <div className="crumb">
            <span style={{ cursor: 'pointer' }} onClick={() => navigate('home')}>Benchmark</span>
            <span style={{ margin: '0 8px' }}>/</span>
            <span>Leaderboard</span>
          </div>
          <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 32 }}>
            <h1 style={{ flex: 1, margin: 0, fontSize: 72, fontFamily: 'var(--ff-display)', fontWeight: 300, letterSpacing: '-0.025em' }}>
              The <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>leaderboard</em>
            </h1>
            <button className="btn" onClick={() => navigate('share')}>Share ↗</button>
          </div>
          <div className="stat-strip">
            <div className="stat"><div className="label">Models</div><div className="value mono">{modelCount || '—'}</div></div>
            <div className="stat"><div className="label">Community prompts</div><div className="value mono">{community.data?.items?.length ?? '—'}</div></div>
            <div className="stat"><div className="label">Markets tracked</div><div className="value mono">{totals.markets || '—'}</div></div>
            <div className="stat"><div className="label">Volume</div><div className="value mono">{formatMoney(totals.volume || 0)}</div></div>
          </div>
        </div>
      </div>

      <section className="container" style={{ padding: '40px 32px 0' }}>
        <div className="tabs">
          <button className={`tab ${tab === 'official' ? 'active' : ''}`} onClick={() => setTab('official')}>
            Official · {modelCount} models
          </button>
          <button className={`tab ${tab === 'community' ? 'active' : ''}`} onClick={() => setTab('community')}>
            Community · {community.data?.items?.length ?? '—'} prompts
          </button>
        </div>

        {tab === 'official' && (
          <>
            <div className="between" style={{ marginBottom: 22 }}>
              <div className="filter-row">
                <button className={`fchip ${cat === 'all' ? 'active' : ''}`} onClick={() => setCat('all')}>All categories</button>
                {categories.map((c) => (
                  <button key={c.slug} className={`fchip ${cat === c.slug ? 'active' : ''}`} onClick={() => setCat(c.slug)}>{c.name}</button>
                ))}
              </div>
              <div className="filter-row">
                {['7d', '30d', '90d', 'all'].map((w) => (
                  <button key={w} className={`fchip ${tw === w ? 'active' : ''}`} onClick={() => setTw(w)}>{w === 'all' ? 'All time' : w}</button>
                ))}
              </div>
            </div>

            {/* Accuracy chart — per-model over time with version-change markers */}
            <div style={{ marginBottom: 32 }}>
              <div className="between" style={{ marginBottom: 12 }}>
                <div>
                  <div className="uppercase faint">
                    Accuracy · {tw === 'all' ? 'all time' : `last ${tw}`}
                  </div>
                  <div className="mono faint" style={{ fontSize: 11, marginTop: 4 }}>
                    One point per day of predictions. Faded vertical lines mark version changes — full history in the table below.
                  </div>
                </div>
              </div>
              {timeseries.loading && !timeseries.data ? <Loading label="Loading chart…" height={280} /> : (
                <ModelAccuracyChart
                  byModel={timeseries.data?.byModel || {}}
                  versionsByModel={versions.data?.items || {}}
                  days={timeseries.data?.days || 30}
                />
              )}
            </div>

            {official.error ? <ApiError error={official.error} /> : official.loading && !official.data ? <Loading label="Loading leaderboard…" /> : (
              <table className="tbl">
                <thead>
                  <tr>
                    <th style={{ width: 50 }}>#</th>
                    <th>Model</th>
                    <th className="num">Accuracy <span className="mono faint" style={{ fontSize: 9, marginLeft: 4 }}>binary, resolved</span></th>
                    <th className="num">Avg confidence <span className="mono faint" style={{ fontSize: 9, marginLeft: 4 }}>prob assigned to truth</span></th>
                    <th className="num">Market agreement <span className="mono faint" style={{ fontSize: 9, marginLeft: 4 }}>pre-resolution proxy</span></th>
                    <th className="num">Predictions</th>
                    <th className="num">Resolved</th>
                    <th className="num">Avg edge</th>
                    <th>Provider</th>
                  </tr>
                </thead>
                <tbody>
                  {(official.data?.items || []).map((row) => {
                    const isOpen = expanded === row.modelId;
                    return (
                      <React.Fragment key={row.modelId}>
                        <tr style={{ cursor: 'pointer' }}
                            onClick={() => setExpanded(isOpen ? null : row.modelId)}>
                          <td className={`rnk ${row.rank === 1 ? 't1' : row.rank === 2 ? 't2' : row.rank === 3 ? 't3' : ''}`}>{row.rank}</td>
                          <td>
                            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                              <span aria-hidden style={{
                                display: 'inline-block', width: 10, fontSize: 10,
                                transform: isOpen ? 'rotate(90deg)' : 'rotate(0deg)',
                                transition: 'transform .15s ease', opacity: 0.5,
                              }}>▸</span>
                              <span style={{ width: 10, height: 10, borderRadius: '50%', background: row.color, opacity: row.enabled ? 1 : 0.35 }} />
                              <span style={{ fontFamily: 'var(--ff-display)', fontSize: 18, fontWeight: 400 }}>{row.modelLabel}</span>
                              {!row.enabled && <span className="mono faint" style={{ fontSize: 10 }}>· no API key</span>}
                            </span>
                          </td>
                          <td className="num mono tnum" style={{ fontSize: 18 }}>
                            {row.accuracy == null
                              ? <span className="faint" title="No resolved markets yet">—</span>
                              : `${Math.round(row.accuracy * 100)}%`}
                          </td>
                          <td className="num mono tnum" style={{ fontSize: 16 }}
                              title="Average probability assigned to the actual outcome. 50% = coin flip, 100% = always confident and right.">
                            {row.avgConfidence == null
                              ? <span className="faint">—</span>
                              : `${Math.round(row.avgConfidence * 100)}%`}
                          </td>
                          <td className="num mono tnum dim" style={{ fontSize: 14 }}>
                            {row.predictions === 0 ? '—' : `${Math.round(row.marketAgreement * 100)}%`}
                            {row.predictions > 0 && (
                              <span className="mono faint" style={{ fontSize: 10, marginLeft: 6 }}>
                                {row.agreed}/{row.predictions}
                              </span>
                            )}
                          </td>
                          <td className="num mono tnum dim">{row.predictions}</td>
                          <td className="num mono tnum dim">
                            {row.resolvedCount > 0
                              ? row.resolvedCount
                              : <span className="faint">0</span>}
                          </td>
                          <td className={`num mono tnum ${row.avgEdge > 0 ? 'pos' : row.avgEdge < 0 ? 'neg' : 'dim'}`}>
                            {row.avgEdge ? `${row.avgEdge > 0 ? '+' : ''}${Math.round(row.avgEdge * 100)}pp` : '—'}
                          </td>
                          <td className="dim mono" style={{ fontSize: 11 }}>{row.provider}</td>
                        </tr>
                        {isOpen && (
                          <tr>
                            <td colSpan={9} style={{ padding: 0, background: 'rgba(0,0,0,0.025)' }}>
                              <PerCategoryBreakdown row={row} categories={categories} navigate={navigate} />
                            </td>
                          </tr>
                        )}
                      </React.Fragment>
                    );
                  })}
                </tbody>
              </table>
            )}
            <div className="mono faint" style={{ fontSize: 11, marginTop: 12, lineHeight: 1.5, maxWidth: 820 }}>
              <strong>Accuracy</strong> — binary ground-truth (right side of 50% on resolved markets).
              <br />
              <strong>Avg confidence</strong> — the value-based version. Average probability the model put on the actual outcome. Saying 90% YES on a YES that resolved counts more than 51% YES; saying 90% NO on the same market is a worse miss than 51% NO. 50% means coin flips, higher is more confidently right.
              <br />
              <strong>Market agreement</strong> — a pre-resolution proxy. How often the model lands on the same side of 50% as the live market line.
            </div>

            {/* Version history — at the bottom, less important than the standings */}
            <div style={{ marginTop: 48 }}>
              <ModelVersionsWidget versions={versions.data?.items || {}} />
            </div>
          </>
        )}

        {tab === 'community' && (
          <>
            {/* Top-N community prompts over time. Auto-fits the window, so the
                line cluster doesn't look sparse when prompts are new. */}
            <div style={{ marginBottom: 28 }}>
              <div className="uppercase faint" style={{ fontSize: 10, letterSpacing: '0.08em', marginBottom: 8 }}>
                accuracy · top community prompts · last 30 days
              </div>
              {(() => {
                const ts = communityTimeseries.data;
                const series = (ts?.prompts || []).map((p) => ({
                  id: p.promptId,
                  label: p.author ? `${p.name} · ${p.author}` : p.name,
                  color: p.modelColor,
                  points: (ts?.byPrompt?.[p.promptId] || []),
                }));
                return <AccuracyLineChart series={series} days={30} height={220} />;
              })()}
            </div>

            {community.error ? <ApiError error={community.error} /> : community.loading && !community.data ? <Loading label="Loading community…" /> : (
              (community.data?.items || []).length === 0 ? (
                <div className="panel" style={{ padding: 36, textAlign: 'center' }}>
                  <div className="dim" style={{ marginBottom: 12 }}>No community prompts yet.</div>
                  <button className="btn btn-accent" onClick={() => navigate('profile')}>Track the first one →</button>
                </div>
              ) : (
                <>
                <table className="tbl">
                  <thead>
                    <tr>
                      <th style={{ width: 50 }}>#</th>
                      <th>Prompt</th>
                      <th>Author</th>
                      <th>Model</th>
                      <th className="num">Accuracy <span className="mono faint" style={{ fontSize: 9, marginLeft: 4 }}>resolved</span></th>
                      <th className="num">Resolved</th>
                      <th className="num">Predictions</th>
                    </tr>
                  </thead>
                  <tbody>
                    {(community.data?.items || []).map((row) => (
                      <tr key={row.promptId}>
                        <td className={`rnk ${row.rank === 1 ? 't1' : row.rank === 2 ? 't2' : row.rank === 3 ? 't3' : ''}`}>{row.rank}</td>
                        <td style={{ fontFamily: 'var(--ff-display)', fontSize: 18, fontWeight: 400 }}>{row.name}</td>
                        <td>
                          <span className="mono" style={{ fontSize: 12 }}>
                            {row.user?.handle ? '@' + row.user.handle : (row.user?.name || '—')}
                          </span>
                        </td>
                        <td>
                          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                            <span style={{ width: 8, height: 8, borderRadius: '50%', background: row.modelColor }} />
                            <span className="mono" style={{ fontSize: 12 }}>{row.modelLabel}</span>
                          </span>
                        </td>
                        <td className="num mono tnum" style={{ fontSize: 18 }}>
                          {row.accuracy == null
                            ? <span className="faint" title="No predictions resolved yet">—</span>
                            : `${Math.round(row.accuracy * 100)}%`}
                        </td>
                        <td className="num mono tnum dim">
                          {row.resolvedCount > 0 ? `${row.correct}/${row.resolvedCount}` : <span className="faint">0</span>}
                        </td>
                        <td className="num mono tnum dim">{row.predictions}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
                <div className="mono faint" style={{ fontSize: 11, marginTop: 12, lineHeight: 1.5, maxWidth: 720 }}>
                  Accuracy here is <strong>ground-truth only</strong> — % of predictions that matched the resolved market outcome. A prompt without resolved predictions shows <strong>—</strong>; it sits below ranked prompts until at least one of its markets resolves.
                </div>
                </>
              )
            )}
          </>
        )}
      </section>

      <div style={{ height: 96 }} />
    </div>
  );
}

// =========================================================================
// ModelVersionsWidget — one row per model with current version + dates of
// any prior versions. Lets you reconcile a bump in accuracy with the version
// change that drove it.
// =========================================================================
function ModelVersionsWidget({ versions }) {
  const { models } = useMeta();
  const has = Object.keys(versions).length > 0;
  if (!has) return null;
  return (
    <div className="panel" style={{ marginBottom: 32 }}>
      <div className="panel-header">
        <h3>Model versions</h3>
        <span className="mono faint" style={{ fontSize: 11 }}>updated on each server boot</span>
      </div>
      <div className="panel-body">
        <table className="tbl">
          <thead>
            <tr>
              <th style={{ width: 200 }}>Model</th>
              <th>Current version</th>
              <th>Since</th>
              <th>Previous</th>
            </tr>
          </thead>
          <tbody>
            {models.map((m) => {
              const rows = (versions[m.id] || []).slice().sort((a, b) => new Date(b.startedAt) - new Date(a.startedAt));
              const current = rows.find((r) => !r.endedAt) || rows[0];
              const prior = rows.filter((r) => r !== current);
              if (!current) return null;
              return (
                <tr key={m.id}>
                  <td>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                      <span style={{ width: 10, height: 10, borderRadius: '50%', background: m.color, opacity: m.enabled ? 1 : 0.35 }} />
                      <span style={{ fontFamily: 'var(--ff-display)', fontSize: 17 }}>{m.label}</span>
                    </span>
                  </td>
                  <td className="mono" style={{ fontSize: 12 }}>{current.modelVersion}</td>
                  <td className="mono dim" style={{ fontSize: 12 }}>
                    {new Date(current.startedAt).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' })}
                  </td>
                  <td className="mono dim" style={{ fontSize: 11 }}>
                    {prior.length === 0 ? '—' : prior.slice(0, 3).map((p) => (
                      <span key={p._id} title={`${new Date(p.startedAt).toLocaleDateString()} → ${p.endedAt ? new Date(p.endedAt).toLocaleDateString() : 'now'}`}
                            style={{ display: 'inline-block', marginRight: 10 }}>
                        {p.modelVersion}
                      </span>
                    ))}
                    {prior.length > 3 && <span className="faint">+{prior.length - 3}</span>}
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// =========================================================================
// PerCategoryBreakdown — the panel that drops down when you click a model
// row. One card per category, showing how that model is doing there.
// Click a card to jump straight to the category page.
// =========================================================================
function PerCategoryBreakdown({ row, categories, navigate }) {
  const cells = row.byCategory || [];
  const byCat = Object.fromEntries(cells.map((c) => [c.category, c]));
  return (
    <div style={{ padding: '20px 24px 24px', borderTop: '1px solid var(--line)' }}>
      <div className="between" style={{ marginBottom: 14 }}>
        <div className="uppercase faint" style={{ fontSize: 10, letterSpacing: '0.08em' }}>
          {row.modelLabel} · per-category breakdown
        </div>
        <div className="mono faint" style={{ fontSize: 10 }}>
          click a category to jump
        </div>
      </div>
      <div style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(auto-fit, minmax(160px, 1fr))',
        gap: 12,
      }}>
        {categories.map((c) => {
          const cell = byCat[c.slug] || { predictions: 0 };
          const empty = !cell.predictions;
          const hasReal = cell.accuracy != null;
          const big = empty
            ? null
            : hasReal
            ? `${Math.round(cell.accuracy * 100)}%`
            : `${Math.round(cell.marketAgreement * 100)}%`;
          return (
            <div
              key={c.slug}
              onClick={() => !empty && navigate('category', { slug: c.slug })}
              style={{
                background: 'var(--bg)',
                border: '1px solid var(--line)',
                borderRadius: 8,
                padding: '12px 14px',
                cursor: empty ? 'default' : 'pointer',
                opacity: empty ? 0.55 : 1,
                transition: 'transform .12s ease, border-color .12s ease',
              }}
              onMouseEnter={(e) => { if (!empty) e.currentTarget.style.borderColor = row.color; }}
              onMouseLeave={(e) => { e.currentTarget.style.borderColor = 'var(--line)'; }}
            >
              <div className="uppercase faint" style={{ fontSize: 10, letterSpacing: '0.06em' }}>
                {c.name}
              </div>
              {empty ? (
                <div className="mono faint" style={{ fontSize: 12, marginTop: 10 }}>
                  no predictions
                </div>
              ) : (
                <>
                  <div className="mono tnum" style={{
                    fontSize: 24, marginTop: 6, lineHeight: 1.1,
                    color: hasReal ? 'var(--ink)' : 'var(--ink-dim, var(--ink))',
                  }}>
                    {big}
                  </div>
                  <div className="mono faint" style={{ fontSize: 10, marginTop: 2 }}>
                    {hasReal
                      ? `${cell.correct}/${cell.resolvedCount} resolved`
                      : `${cell.agreed}/${cell.predictions} agreed`}
                  </div>
                  {cell.avgConfidence != null && (
                    <div className="mono faint" style={{ fontSize: 10, marginTop: 4 }}>
                      conf · {Math.round(cell.avgConfidence * 100)}%
                    </div>
                  )}
                </>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

window.LeaderboardPage = LeaderboardPage;
window.ModelVersionsWidget = ModelVersionsWidget;
window.PerCategoryBreakdown = PerCategoryBreakdown;
