/**
 * Regression guard — a ban must replay in the reconnect delta so a client that missed the
 * ephemeral `user-hidden` SSE (most acutely the unattended diashow projector) still evicts
 * the banned user's already-loaded slides instead of cycling them all night.
 *
 * A ban is NOT a soft-delete (no `upload.deleted_at`), so it never appears in the delta's
 * `deleted_ids`. The fix: `uploads_hidden_at` stamps when a user became hidden, and
 * `/feed/delta` returns `hidden_user_ids` for users hidden since the client's cursor. The
 * client (feed + diashow) evicts all uploads from those users.
 */
import { test, expect } from '../../fixtures/test';
import { seedUpload } from '../../helpers/seed';
import { BASE } from '../../helpers/env';

async function feedDelta(jwt: string, since: string): Promise<any> {
  const res = await fetch(`${BASE}/api/v1/feed/delta?since=${encodeURIComponent(since)}`, {
    headers: { Authorization: `Bearer ${jwt}` },
  });
  expect(res.status).toBe(200);
  return res.json();
}

test.describe('Realtime — ban replays in the reconnect delta (H1 audit fix)', () => {
  test('a ban since the cursor is in hidden_user_ids; a ban before it is not', async ({
    host,
    guest,
    api,
  }) => {
    const g = await guest('BanReplayGuest');
    await seedUpload(g.jwt, { caption: 'to be hidden' });

    // Cursor BEFORE the ban — this is the "last-seen" point a disconnected client holds.
    const before = await feedDelta(host.jwt, '2000-01-01T00:00:00Z');
    const cursorBefore: string = before.server_time;
    expect(before.hidden_user_ids).not.toContain(g.userId); // not hidden yet

    // Ban the guest (read-only ban; content hidden everywhere).
    await api.banUser(host.jwt, g.userId);

    // A delta from the pre-ban cursor MUST surface the ban so the client can evict.
    const afterBan = await feedDelta(host.jwt, cursorBefore);
    expect(
      afterBan.hidden_user_ids,
      'ban replayed to a client that missed the live event'
    ).toContain(g.userId);

    // And a delta from a cursor AFTER the ban must NOT re-surface it (the `>= since` filter
    // means a client already past the ban isn't told again forever).
    const cursorAfter: string = afterBan.server_time;
    const afterCursor = await feedDelta(host.jwt, cursorAfter);
    expect(afterCursor.hidden_user_ids).not.toContain(g.userId);

    // Unban clears the timestamp, so a fresh ban later would replay again.
    await api.unbanUser(host.jwt, g.userId);
    const afterUnban = await feedDelta(host.jwt, '2000-01-01T00:00:00Z');
    expect(afterUnban.hidden_user_ids).not.toContain(g.userId);
  });
});
