/**
 * SSE reconnection after tab background. USER_JOURNEYS.md §17 / edge cases.
 *
 * The app closes the EventSource on `document.hidden` and reopens it (minting a
 * fresh ticket + new EventSource) when the tab becomes visible again — see
 * frontend/src/lib/sse.ts. We assert the reconnect by counting stream-open
 * requests rather than event delivery, which keeps the test fast and independent
 * of the reverse proxy's SSE buffering.
 */
import { test, expect } from '../../fixtures/test';
import { trackStreamOpens } from '../../helpers/sse';

test.describe('Feed — SSE behavior', () => {
  test('backgrounding then foregrounding the tab opens a fresh SSE connection', async ({
    page,
    guest,
    signIn,
  }) => {
    const g = await guest('SseReconnect');
    const streamOpens = trackStreamOpens(page);

    await signIn(page, g); // lands on /feed, which calls connectSse() on mount
    // Initial connection established.
    await expect.poll(streamOpens, { timeout: 10_000 }).toBeGreaterThanOrEqual(1);

    // Background: the visibility handler reads document.hidden, so override that
    // (not just visibilityState) before dispatching, or the close never fires.
    // disconnectSse() closes the EventSource and clears any reconnect timer, so no
    // new stream opens while hidden.
    await page.evaluate(() => {
      Object.defineProperty(document, 'hidden', { configurable: true, get: () => true });
      Object.defineProperty(document, 'visibilityState', {
        configurable: true,
        get: () => 'hidden',
      });
      document.dispatchEvent(new Event('visibilitychange'));
    });
    // Snapshot the count AFTER backgrounding — this baselines out the initial open (and
    // any spurious native/error reconnect before now), so the assertion below can only
    // be satisfied by a NEW open attributable to the foreground event itself.
    const afterHidden = streamOpens();

    // Foreground again → connectSse() mints a new ticket and opens a new EventSource.
    await page.evaluate(() => {
      Object.defineProperty(document, 'hidden', { configurable: true, get: () => false });
      Object.defineProperty(document, 'visibilityState', {
        configurable: true,
        get: () => 'visible',
      });
      document.dispatchEvent(new Event('visibilitychange'));
    });

    // The reconnect is a brand-new stream GET that appears only after foregrounding.
    await expect.poll(streamOpens, { timeout: 10_000 }).toBeGreaterThan(afterHidden);

    // And the app is still functional.
    await expect(page.getByRole('link', { name: 'Galerie' })).toBeVisible();
  });
});
