import {
  test as base,
  chromium,
  type Page,
  type BrowserContext,
  type Browser
} from '@playwright/test';
import { join } from 'node:path';
import { installTestServerEndpoint } from '../helpers/seed-test-endpoint';
import { startTestServer, type TestServerHandle } from '../helpers/test-server';

export interface Client {
  page: Page;
  context: BrowserContext;
}

interface MultiClientFixture {
  createClient: () => Promise<Client>;
  testServer: TestServerHandle;
}

const FAKE_AUDIO_FILE = join(__dirname, 'test-tone.wav');
const CHROMIUM_FAKE_MEDIA_ARGS = [
  '--use-fake-device-for-media-stream',
  '--use-fake-ui-for-media-stream',
  `--use-file-for-fake-audio-capture=${FAKE_AUDIO_FILE}`,
  '--autoplay-policy=no-user-gesture-required'
];

export const test = base.extend<MultiClientFixture>({
  testServer: async ({ playwright: _playwright }, use: (testServer: TestServerHandle) => Promise<void>) => {
    const testServer = await startTestServer();

    await use(testServer);
    await testServer.stop();
  },

  createClient: async ({ testServer }, use) => {
    const browsers: Browser[] = [];
    const clients: Client[] = [];
    const factory = async (): Promise<Client> => {
      // Launch a dedicated browser per client so each gets its own fake
      // audio device - shared browsers can starve the first context's
      // audio capture under load.
      const browser = await chromium.launch({ args: CHROMIUM_FAKE_MEDIA_ARGS });

      browsers.push(browser);

      const context = await browser.newContext({
        permissions: ['microphone', 'camera'],
        baseURL: 'http://localhost:4200'
      });

      await installTestServerEndpoint(context, testServer.port);

      const page = await context.newPage();

      clients.push({ page, context });
      return { page, context };
    };

    await use(factory);

    for (const client of clients) {
      await client.context.close();
    }

    for (const browser of browsers) {
      await browser.close();
    }
  }
});

export { expect } from '@playwright/test';
