// Statistik — admin dashboard. Two sub-views toggled at the top:
//
//   1. Übersicht — submission counts, ingame metrics, leaderboards.
//   2. Verlauf   — paginated history of every decided submission
//                  (accepted + rejected, newest first), with admin
//                  three-dot menus to re-open / re-decide.
//
// Both views share this page so admins have one consolidated dashboard
// for "what happened" instead of two separate routes.
//
// Data: Übersicht hits /api/stats (server-side aggregation) once.
// Verlauf hits the paginated /api/catalog with status=decided so it
// stays fast even at 10k+ decided tracks.

function StatsScreen({ me, refresh: refreshApp }) {
  const [tab, setTab] = React.useState('overview');   // 'overview' | 'verlauf'
  const [stats, setStats] = React.useState(null);
  const [err, setErr] = React.useState('');

  const refresh = React.useCallback(async () => {
    try {
      const data = await Api.stats();
      setStats(data);
      setErr('');
    } catch (e) {
      setErr(e.message);
    }
  }, []);

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

  if (me.group !== 'admin') {
    return (
      <div style={{ padding: '60px 32px 140px', maxWidth: 620, margin: '0 auto' }}>
        <Glass radius={20} padding={36} style={{ textAlign: 'center' }}>
          <ApIcon name="shield" size={32} color="var(--gold)"/>
          <h2 style={{ fontSize: 20, fontWeight: 800, margin: '12px 0 6px' }}>Nur Admins</h2>
          <div style={{ fontSize: 13, color: 'var(--fg-3)' }}>Dieser Bereich ist Admins vorbehalten.</div>
        </Glass>
      </div>
    );
  }

  if (err) {
    return (
      <div style={{ padding: '28px 32px', maxWidth: 1100, margin: '0 auto' }}>
        <Glass radius={20} padding={32} style={{
          textAlign: 'center', color: 'var(--danger)',
          border: '1px solid rgba(255,110,138,0.45)',
        }}>{err}</Glass>
      </div>
    );
  }

  if (!stats) {
    return (
      <div style={{ padding: '60px 32px', textAlign: 'center', color: 'var(--fg-3)' }}>
        Lade Statistiken…
      </div>
    );
  }

  const acceptRatio = stats.counts.total > 0
    ? Math.round((stats.counts.accepted / stats.counts.total) * 100)
    : 0;

  return (
    <div style={{ padding: '32px 36px 140px', maxWidth: 1280, margin: '0 auto' }}>

      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', marginBottom: 18 }}>
        <div>
          <Eyebrow style={{ marginBottom: 6 }}>
            {tab === 'overview' ? 'Übersicht · letzte 30 Tage' : 'Verlauf · letzte 25 hochgeladen'}
          </Eyebrow>
          <h1 style={{ fontWeight: 800, fontSize: 40, lineHeight: 1.05, letterSpacing: '-0.02em', margin: 0 }}>
            Statistik
          </h1>
        </div>
        {tab === 'overview' && (
          <Button variant="secondary" size="sm" icon="arrows-rotate" onClick={refresh}>
            Neu laden
          </Button>
        )}
      </div>

      {/* Sub-tab toggle */}
      <div style={{ display: 'flex', gap: 6, marginBottom: 22, flexWrap: 'wrap' }}>
        <SubTab active={tab === 'overview'} onClick={() => setTab('overview')} icon="chart-line">
          Übersicht
        </SubTab>
        <SubTab active={tab === 'verlauf'} onClick={() => setTab('verlauf')} icon="clock">
          Verlauf
        </SubTab>
      </div>

      {tab === 'verlauf' && <VerlaufList me={me} refresh={refreshApp}/>}
      {tab === 'overview' && <OverviewBody stats={stats} me={me}/>}
    </div>
  );
}

// Sub-tab toggle button. Looks like the header tab chips but smaller
// because it lives inside the page instead of in the global nav.
function SubTab({ active, onClick, icon, children }) {
  return (
    <button onClick={onClick} style={{
      display: 'flex', alignItems: 'center', gap: 7,
      padding: '8px 14px', borderRadius: 10,
      border: 'none', cursor: 'pointer',
      background: active ? 'rgba(169,114,244,0.18)' : 'transparent',
      color: active ? 'var(--lila-200)' : 'var(--fg-2)',
      fontSize: 13.5, fontWeight: 600, opacity: active ? 1 : 0.78,
      fontFamily: 'inherit',
      transition: 'background 150ms var(--ease-out)',
    }}>
      <ApIcon name={icon} size={13}/>
      {children}
    </button>
  );
}

// Verlauf — "letzte 25 hochgeladene Tracks". Quick "what's new"
// snapshot for admins, not a deep history archive. No pagination
// (just the latest 25), no filters; if you want to dig deeper, the
// home library has full sort + filter + 50-per-page paging for
// accepted tracks.
//
// Includes pending tracks too — useful for admins to see what just
// came in even before the AudD copyright worker has had a chance to
// process them. Status is sorted by upload time descending.
const VERLAUF_LIMIT = 25;

function VerlaufList({ me, refresh: refreshApp }) {
  const audio = useAudioStatus();
  const isAdmin = canForceAccept(me);
  const [items, setItems] = React.useState([]);
  const [loading, setLoading] = React.useState(true);

  const load = React.useCallback(async () => {
    setLoading(true);
    try {
      // No status filter — we want the most recent uploads regardless
      // of decision state. The catalog endpoint defaults to sort=newest
      // by submitted_at when no other sort is set.
      const out = await Api.catalog({ sort: 'newest', limit: VERLAUF_LIMIT });
      setItems(out.items);
    } catch (e) {
      toast.error('Verlauf laden fehlgeschlagen: ' + e.message);
    } finally {
      setLoading(false);
    }
  }, []);

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

  // Wrap the app-level refresh so admin actions on a row also re-
  // pull this list (e.g. status override flips the pill).
  const refreshAll = async () => {
    if (refreshApp) await refreshApp();
    await load();
  };

  if (loading && items.length === 0) {
    return (
      <Glass radius={20} padding={32} style={{ textAlign: 'center', color: 'var(--fg-3)' }}>
        Lade Verlauf…
      </Glass>
    );
  }

  if (items.length === 0) {
    return (
      <EmptyState
        icon="clock"
        title="Noch keine Uploads"
        description="Sobald jemand einen Track hochlädt, taucht er hier auf."
      />
    );
  }

  return (
    <Glass radius={20} padding={0}>
      {items.map((s, i) => {
        const t = tally(s);
        const submitter = playerByIdent(s.identifier);
        return (
          <TrackRow key={s.id} track={s}
            border={i < items.length - 1}
            meta={
              <>
                <ArtistLink identifier={s.identifier} name={s.artist} size={12}/>
                <span style={{ color: 'var(--fg-4)' }}>·</span>
                von <PlayerName player={submitter} size={12} opacity={1}/>
                <span style={{ color: 'var(--fg-4)' }}>·</span>
                {timeAgo(s.submittedAt)}
              </>
            }
            trailing={
              <>
                <div style={{
                  fontSize: 11.5, color: 'var(--fg-3)', minWidth: 90, textAlign: 'right',
                  fontVariantNumeric: 'tabular-nums',
                }}>
                  <span style={{ color: 'var(--success)' }}>{t.accepts}</span> /{' '}
                  <span style={{ color: 'var(--danger)' }}>{t.rejects}</span>
                </div>
                <StatusPill status={s.status}/>
                <ShareButton track={s}/>
                <AdminMenu sub={s} refresh={refreshAll}/>
              </>
            }/>
        );
      })}
    </Glass>
  );
}

// Reusable pagination footer. Page number set + prev/next, plus the
// "X-Y von Z" position readout in the centre. Disabled-styling on
// the edge buttons so the user gets visual feedback that they're at
// the first or last page.
function Pagination({ page, totalPages, total, pageSize, onPage }) {
  const from = page * pageSize + 1;
  const to   = Math.min(total, (page + 1) * pageSize);
  return (
    <div style={{
      display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 14,
      padding: '16px 4px 0', flexWrap: 'wrap',
    }}>
      <span style={{ fontSize: 12, color: 'var(--fg-3)' }}>
        <span style={{ fontVariantNumeric: 'tabular-nums', color: 'var(--fg-2)' }}>{from}-{to}</span>
        {' '}von{' '}
        <span style={{ fontVariantNumeric: 'tabular-nums', color: 'var(--fg-2)' }}>{numDE(total)}</span>
      </span>
      <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
        <Button variant="ghost" size="sm" icon="chevron-left"
          disabled={page <= 0}
          onClick={() => onPage(Math.max(0, page - 1))}>
          Zurück
        </Button>
        <span style={{
          fontSize: 12, color: 'var(--fg-3)', fontVariantNumeric: 'tabular-nums',
          padding: '0 8px',
        }}>
          Seite {page + 1} / {totalPages}
        </span>
        <Button variant="ghost" size="sm" iconRight="chevron-right"
          disabled={page >= totalPages - 1}
          onClick={() => onPage(Math.min(totalPages - 1, page + 1))}>
          Weiter
        </Button>
      </div>
    </div>
  );
}

// Overview body — extracted from the old StatsScreen so we can render
// it conditionally inside the sub-tab toggle. Pure presentational.
function OverviewBody({ stats, me }) {
  if (!stats) {
    return (
      <Glass radius={20} padding={32} style={{ textAlign: 'center', color: 'var(--fg-3)' }}>
        Lade Statistiken…
      </Glass>
    );
  }
  const acceptRatio = stats.counts.total > 0
    ? Math.round((stats.counts.accepted / stats.counts.total) * 100)
    : 0;

  return (
    <>

      {/* Submission counts */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 14, marginBottom: 14 }}>
        <BigStat label="Insgesamt"      value={numDE(stats.counts.total)}    accent="var(--lila-300)" icon="layer-group"/>
        <BigStat label="In Prüfung"     value={numDE(stats.counts.pending)}  accent="var(--warning)"  icon="clock"/>
        <BigStat label="Veröffentlicht" value={numDE(stats.counts.accepted)} accent="var(--success)"  icon="check"/>
        <BigStat label="Abgelehnt"      value={numDE(stats.counts.rejected)} accent="var(--danger)"   icon="x"/>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14, marginBottom: 26 }}>
        <BigStat label="Akzeptanz-Quote" value={`${acceptRatio}%`}                    accent="var(--success)" icon="chart-line"/>
        <BigStat label="Letzte 24h"      value={numDE(stats.submissionsLast24h || 0)} accent="var(--info)"    icon="bolt"/>
        <BigStat label="Letzte 7 Tage"   value={numDE(stats.submissionsLast7d  || 0)} accent="var(--info)"    icon="calendar"/>
      </div>

      {/* Ingame */}
      <Eyebrow style={{ margin: '4px 0 14px' }}>Ingame</Eyebrow>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 14, marginBottom: 26 }}>
        <BigStat label="Streams"  value={numDE(stats.streams   ?? 0)} accent="var(--coral)"    icon="headphones"/>
        <BigStat label="Plays"    value={numDE(stats.plays     ?? 0)} accent="var(--magenta)"  icon="play"/>
        <BigStat label="Likes"    value={numDE(stats.likes     ?? 0)} accent="var(--coral)"    icon="heart"/>
        <BigStat label="Hörer"    value={numDE(stats.listeners ?? 0)} accent="var(--lila-300)" icon="user-group"/>
      </div>

      {/* Leaderboards row 1 */}
      <div style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: 14 }}>
        <TrackLeaderboard
          title="Meist gehört"
          metric="Streams"
          empty="Noch keine Streams."
          rows={stats.topTracks || []}/>
        <Leaderboard
          title="Top Creators"
          metric="Tracks"
          empty="Noch keine Tracks hochgeladen."
          rows={stats.topSubmitters || []}/>
      </div>

      {/* Leaderboards row 2 */}
      <div style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: 14, marginTop: 14 }}>
        <Leaderboard
          title="Top Voter"
          metric="Stimmen"
          empty="Noch niemand abgestimmt."
          rows={stats.topVoters || []}/>
        <Glass radius={20} padding={22} style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
          <div style={{
            width: 44, height: 44, borderRadius: 12,
            background: 'rgba(255,194,103,0.18)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}>
            <ApIcon name="ban" size={20} color="var(--warning)"/>
          </div>
          <div>
            <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--foam)' }}>
              {stats.blockCount} {stats.blockCount === 1 ? 'gesperrter Spieler' : 'gesperrte Spieler'}
            </div>
            <div style={{ fontSize: 12, color: 'var(--fg-3)' }}>Verwalten unter „Sperren".</div>
          </div>
        </Glass>
      </div>
    </>
  );
}

// Track-flavoured leaderboard. Shows the cover + title + artist
// instead of an avatar + player name. Used for "Meist gehört".
function TrackLeaderboard({ title, metric, empty, rows }) {
  return (
    <Glass radius={20} padding={22}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
        <Eyebrow>{title}</Eyebrow>
        <span style={{ fontSize: 11, color: 'var(--fg-3)' }}>{metric}</span>
      </div>
      {rows.length === 0
        ? <div style={{ fontSize: 13, color: 'var(--fg-3)' }}>{empty}</div>
        : rows.map((t, i) => (
          <div key={t.id} style={{
            display: 'flex', alignItems: 'center', gap: 12, padding: '10px 0',
            borderBottom: i < rows.length - 1 ? '1px solid var(--border-hairline)' : 'none',
          }}>
            <Rank n={i + 1}/>
            <Cover colors={t.cover} src={t.coverUrl} size={38} radius={10}/>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 13.5, fontWeight: 700, color: 'var(--foam)',
                whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{t.title}</div>
              <div style={{ fontSize: 11.5, color: 'var(--fg-3)' }}>{t.artist}</div>
            </div>
            <div style={{
              fontSize: 13.5, fontWeight: 700, color: 'var(--coral)',
              fontVariantNumeric: 'tabular-nums',
            }}>{numDE(t.streams)}</div>
          </div>
        ))}
    </Glass>
  );
}

// Creator/voter leaderboard. Shows ONLY the artist display name —
// never the underlying char/ESX name. The server resolves the name
// via `st_music_artists.name` with a fallback to the most-recent
// track's `artist` string, and ships it as `r.artist`. If even that
// is missing (rare: a voter who never uploaded and has no profile)
// we render the bare identifier as a last resort.
//
// Count comes back as `r.n` (matches the SQL `COUNT(*) AS n` alias);
// we were reading `r.count` here previously and always showed 0.
function Leaderboard({ title, metric, empty, rows }) {
  return (
    <Glass radius={20} padding={22}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
        <Eyebrow>{title}</Eyebrow>
        <span style={{ fontSize: 11, color: 'var(--fg-3)' }}>{metric}</span>
      </div>
      {rows.length === 0
        ? <div style={{ fontSize: 13, color: 'var(--fg-3)' }}>{empty}</div>
        : rows.map((r, i) => (
          <div key={r.identifier} style={{
            display: 'flex', alignItems: 'center', gap: 12, padding: '10px 0',
            borderBottom: i < rows.length - 1 ? '1px solid var(--border-hairline)' : 'none',
          }}>
            <Rank n={i + 1}/>
            <div style={{ flex: 1, minWidth: 0 }}>
              {r.artist
                ? <ArtistLink identifier={r.identifier} name={r.artist} size={13.5} color="var(--foam)" style={{ fontWeight: 700 }}/>
                : <span style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--fg-3)' }}>
                    {r.identifier}
                  </span>}
            </div>
            <div style={{ fontSize: 13.5, fontWeight: 700, color: 'var(--coral)', fontVariantNumeric: 'tabular-nums' }}>
              {numDE(r.n)}
            </div>
          </div>
        ))}
    </Glass>
  );
}

// Single big-number stat card. Used 11× on this screen.
function BigStat({ label, value, accent, icon }) {
  return (
    <Glass radius={18} padding="20px 22px 18px">
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
        <div style={{
          width: 28, height: 28, borderRadius: 8,
          background: `${accent.replace('var(--', 'rgba(255,255,255,').slice(0, -1)}, 0.15)`,
          backgroundColor: 'rgba(196,154,255,0.10)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          <ApIcon name={icon} size={13} color={accent}/>
        </div>
        <Eyebrow>{label}</Eyebrow>
      </div>
      <div style={{
        fontWeight: 800, fontSize: 36, lineHeight: 1,
        color: accent, letterSpacing: '-0.02em',
        fontVariantNumeric: 'tabular-nums',
      }}>{value}</div>
    </Glass>
  );
}

function Rank({ n }) {
  return (
    <div style={{
      width: 22, fontSize: 13, color: 'var(--fg-4)', textAlign: 'center',
      fontWeight: 800, fontVariantNumeric: 'tabular-nums',
    }}>{n}</div>
  );
}

window.StatsScreen = StatsScreen;
