// Audit-log viewer — admin/mod surface.
//
// Read-only; the entries themselves are written by the action sites
// (force-accept, delete, block etc) so this screen just renders what
// the server hands back. Default fetch is "last 200", quick-filter
// chip row narrows by action, auto-refresh every 30s so an open tab
// during an incident gets new events without manual reload.

const ACTION_FILTERS = [
  { id: '',                                  label: 'Alle' },
  { id: 'auth.login',                        label: 'Logins' },
  { id: 'auth.login-failure',                label: 'Login-Fehler' },
  { id: 'submission.force-accept',           label: 'Veröffentlicht' },
  { id: 'submission.force-reject',           label: 'Abgelehnt' },
  { id: 'submission.delete',                 label: 'Gelöscht' },
  { id: 'submission.status-override',        label: 'Status-Override' },
  { id: 'submission.block-user',             label: 'User gesperrt' },
  { id: 'submission.copyright-rejected',     label: 'Urheberrechts-Reject' },
  { id: 'submission.copyright-skip',         label: 'Copyright-Skip' },
  { id: 'submission.cover-changed',          label: 'Cover geändert' },
  { id: 'submission.edit',                   label: 'Metadaten bearbeitet' },
  { id: 'block.add',                         label: 'Sperre hinzugefügt' },
  { id: 'block.remove',                      label: 'Sperre aufgehoben' },
  { id: 'report.dismiss',                    label: 'Meldung verworfen' },
  { id: 'report.force-delete',               label: 'Meldung → delisted' },
];

function AuditScreen({ me }) {
  const [list, setList] = React.useState(null);
  const [filter, setFilter] = React.useState('');

  const refresh = React.useCallback(async () => {
    try {
      setList(await Api.audit.list({ limit: 200, action: filter || undefined }));
    } catch (e) {
      toast.error('Audit-Log laden fehlgeschlagen: ' + e.message);
    }
  }, [filter]);

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

  React.useEffect(() => {
    const id = setInterval(refresh, 30_000);
    return () => clearInterval(id);
  }, [refresh]);

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

      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', marginBottom: 22 }}>
        <div>
          <Eyebrow style={{ marginBottom: 6 }}>
            {list ? `${list.length} Einträge · append-only` : 'lädt…'}
          </Eyebrow>
          <h1 style={{ fontWeight: 800, fontSize: 40, lineHeight: 1.05, letterSpacing: '-0.02em', margin: 0 }}>
            Audit-Log
          </h1>
          <p style={{ fontSize: 14.5, color: 'var(--fg-2)', marginTop: 8, maxWidth: 720, opacity: 0.82 }}>
            Jede Admin- oder Mod-Aktion gegen Tracks, Sperren oder Meldungen ist hier protokolliert.
            Read-only — Einträge können nicht gelöscht oder geändert werden.
          </p>
        </div>
      </div>

      {/* Action filter chips */}
      <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 18 }}>
        {ACTION_FILTERS.map((f) => {
          const active = filter === f.id;
          return (
            <button key={f.id} onClick={() => setFilter(f.id)} style={{
              padding: '6px 12px', borderRadius: 999, fontSize: 12, fontWeight: 600, cursor: 'pointer',
              background: active ? 'rgba(169,114,244,0.18)' : 'transparent',
              color: active ? 'var(--lila-200)' : 'var(--fg-2)',
              border: active ? '1px solid rgba(169,114,244,0.5)' : '1px solid var(--border-soft)',
              fontFamily: 'inherit',
              transition: 'all 150ms var(--ease-out)',
            }}>
              {f.label}
            </button>
          );
        })}
      </div>

      {list === null ? (
        <Glass radius={20} padding={32} style={{ textAlign: 'center', color: 'var(--fg-3)' }}>
          Lädt…
        </Glass>
      ) : list.length === 0 ? (
        <EmptyState padding={36} description="Keine Einträge mit diesem Filter."/>
      ) : (
        <Glass radius={20} padding={0}>
          {list.map((e, i) => (
            <AuditRow key={e.id} entry={e} border={i < list.length - 1}/>
          ))}
        </Glass>
      )}
    </div>
  );
}

function AuditRow({ entry, border }) {
  const actor = playerByIdent(entry.actor);
  const when = new Date(entry.ts).toLocaleString('de-DE');
  const color = actionColor(entry.action);

  return (
    <div style={{
      display: 'flex', alignItems: 'flex-start', gap: 14, padding: '14px 20px',
      borderBottom: border ? '1px solid var(--border-hairline)' : 'none',
    }}>
      <div style={{
        flex: '0 0 160px',
        fontSize: 11.5, color: 'var(--fg-2)',
        fontFamily: 'var(--font-mono)',
      }}>
        {when}
        <div style={{ fontSize: 10.5, color: 'var(--fg-4)', marginTop: 2 }}>{timeAgo(entry.ts)}</div>
      </div>

      {/* Actor — clipped to 180px so 64-char identifiers don't overflow.
          When we can't resolve the actor to a known player, fall back
          to the raw identifier text. For real identifiers (not the
          synthetic "system" label) make that clickable for admins so
          they can still investigate via the artist detail page. */}
      <div style={{ flex: '0 0 180px', minWidth: 0, overflow: 'hidden' }}>
        {actor ? (
          <PlayerName player={actor} size={12.5} opacity={1}
            style={{ display: 'flex', maxWidth: '100%' }}/>
        ) : entry.actor ? (
          <IdentifierMono identifier={entry.actor} size={12}
            style={{ fontStyle: 'italic' }}/>
        ) : (
          <div style={{ fontSize: 12, color: 'var(--fg-3)', fontStyle: 'italic' }}>
            system
          </div>
        )}
        {entry.actorGroup && (
          <div style={{
            fontSize: 10, color: 'var(--fg-4)', marginTop: 1,
            whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
          }}>
            {entry.actorGroup}
          </div>
        )}
      </div>

      <div style={{ flex: 1, minWidth: 0, overflow: 'hidden' }}>
        <div style={{
          fontSize: 12.5, fontWeight: 700, color,
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        }}>
          {entry.action}
        </div>
        {entry.target && (
          <div style={{
            fontSize: 11, color: 'var(--fg-3)', marginTop: 2,
            fontFamily: 'var(--font-mono)',
            whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
          }} title={entry.target}>
            → {entry.target}
          </div>
        )}
        {entry.details && (
          <div style={{
            fontSize: 11, color: 'var(--fg-3)', marginTop: 4, lineHeight: 1.45,
            wordBreak: 'break-word',
          }}>
            {detailsAsText(entry.details)}
          </div>
        )}
      </div>

      <div style={{
        flex: '0 0 110px', textAlign: 'right',
        fontSize: 10.5, color: 'var(--fg-4)',
        fontFamily: 'var(--font-mono)',
      }}>
        {entry.ip || '—'}
      </div>
    </div>
  );
}

// Simple key:value flattening — keeps the row compact while still
// surfacing the most useful fields. Unknown shapes fall through to
// JSON.stringify for "tell me everything I logged".
function detailsAsText(d) {
  if (!d || typeof d !== 'object') return String(d || '');
  const parts = [];
  for (const k of Object.keys(d)) {
    const v = d[k];
    if (v == null) continue;
    if (typeof v === 'object') parts.push(`${k}=${JSON.stringify(v)}`);
    else                       parts.push(`${k}=${v}`);
  }
  return parts.join(' · ');
}

// Tint the action label based on what it does. Greens for positive
// actions, reds for destructive, gold for warnings, lila for default.
function actionColor(action) {
  if (action.includes('failure'))      return 'var(--danger)';
  if (action.includes('delete'))       return 'var(--danger)';
  if (action.includes('force-accept')) return 'var(--success)';
  if (action.includes('force-reject')) return 'var(--warning)';
  if (action.includes('block'))        return 'var(--coral)';
  if (action.includes('login'))        return 'var(--info)';
  return 'var(--lila-300)';
}

window.AuditScreen = AuditScreen;
