/// <reference types="node" />

import { execFileSync } from 'node:child_process';
import { readFileSync, statSync } from 'node:fs';
import { basename, join } from 'node:path';
import {
  expect,
  test,
  type Download,
  type Locator,
  type Page,
} from '@playwright/test';
import {
  createCancellationFixture,
  GENERATED_FIXTURES,
  observeRuntime,
  type RuntimeObservation,
  type TemporaryMediaFixture,
} from './browser-helpers';

const fixture = (name: string): string => join(GENERATED_FIXTURES, name);

function mediaInput(page: Page): Locator {
  return page.locator('input[type="file"][accept*="audio"]').first();
}

async function importMedia(
  page: Page,
  names: readonly string[]
): Promise<void> {
  await mediaInput(page).setInputFiles(names.map((name) => fixture(name)));
  for (const name of names) {
    const card = page.locator('.media-card').filter({ hasText: name });
    await expect(card.locator('.phase--ready')).toBeVisible({
      timeout: 120_000,
    });
  }
}

async function initializeSingleThread(page: Page): Promise<void> {
  await page.getByText('Engine & browser').click();
  await page.getByLabel('Engine mode').selectOption('force-single-thread');
  await page.getByRole('button', { name: 'Initialize engine' }).click();
  await expect(
    page
      .locator('.engine-pill')
      .filter({ hasText: 'Single-threaded compatibility mode' })
  ).toBeVisible({ timeout: 120_000 });
}

const RESULT_SNAPSHOT_ATTRIBUTE = 'data-playwright-existing-result';

async function markExistingResults(page: Page): Promise<void> {
  await page.locator('.result-card').evaluateAll((cards) => {
    for (const card of cards) {
      card.setAttribute('data-playwright-existing-result', '');
    }
  });
}

function newResultCards(page: Page): Locator {
  return page.locator(`.result-card:not([${RESULT_SNAPSHOT_ATTRIBUTE}])`);
}

function accumulatedOutputName(fileName: string): RegExp {
  const dot = fileName.lastIndexOf('.');
  const stem = dot > 0 ? fileName.slice(0, dot) : fileName;
  const extension = dot > 0 ? fileName.slice(dot) : '';
  const escape = (value: string): string =>
    value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
  return new RegExp(`^${escape(stem)}(?:-\\d+)?${escape(extension)}$`, 'u');
}

async function runForResults(
  page: Page,
  action: () => Promise<void>,
  expectedFileNames: readonly string[],
  options: { verifyMedia?: boolean } = {}
): Promise<readonly Locator[]> {
  await markExistingResults(page);
  await action();

  const cards = expectedFileNames.map((_, index) =>
    newResultCards(page).nth(index)
  );
  await expect
    .poll(
      async () => {
        if ((await cards[0]?.locator('strong').count()) === 1) {
          return 'result';
        }
        if ((await page.getByRole('alert').count()) > 0) {
          const alert = (await page.getByRole('alert').allTextContents()).join(
            ' | '
          );
          const diagnostics =
            (await page.locator('.diagnostics pre').textContent()) ?? '';
          throw new Error(
            `${alert}\n\nFFmpeg diagnostics:\n${diagnostics
              .split('\n')
              .slice(-160)
              .join('\n')}`
          );
        }
        return 'waiting';
      },
      { timeout: 120_000 }
    )
    .toBe('result');
  for (const [index, card] of cards.entries()) {
    await expect(card.locator('strong')).toHaveText(
      accumulatedOutputName(expectedFileNames[index] as string),
      { timeout: 120_000 }
    );
    await expect(card).toContainText(
      /created · (?:verified|verification warning)|completed locally/u,
      { timeout: 120_000 }
    );
    if (options.verifyMedia) {
      await expect(card).toContainText(/verified stream/u, {
        timeout: 120_000,
      });
    }
  }
  await expect(page.getByRole('alert')).toHaveCount(0);
  return cards;
}

async function downloadResult(
  page: Page,
  card: Locator
): Promise<{ download: Download; filePath: string }> {
  const downloadPromise = page.waitForEvent('download');
  await card.locator('button.button--primary').click();
  const download = await downloadPromise;
  const filePath = await download.path();
  expect(filePath).not.toBeNull();
  expect(statSync(filePath as string).size).toBeGreaterThan(0);
  return { download, filePath: filePath as string };
}

function probe(filePath: string): {
  streams?: Array<{
    codec_name?: string;
    codec_type?: string;
    width?: number;
    height?: number;
    avg_frame_rate?: string;
    tags?: Record<string, string>;
    disposition?: Record<string, number>;
  }>;
  format?: { duration?: string; tags?: Record<string, string> };
  chapters?: Array<{ tags?: Record<string, string> }>;
} {
  return JSON.parse(
    execFileSync(
      'ffprobe',
      [
        '-v',
        'error',
        '-show_streams',
        '-show_format',
        '-show_chapters',
        '-of',
        'json',
        filePath,
      ],
      { encoding: 'utf8' }
    )
  ) as ReturnType<typeof probe>;
}

function assertLocalOnly(runtime: RuntimeObservation): void {
  const networkUrls = runtime.requests.filter((url) => /^https?:/u.test(url));
  expect(
    networkUrls.every((url) => new URL(url).origin === 'http://127.0.0.1:4173')
  ).toBe(true);
  const materialFailures = runtime.failedRequests.filter(
    (failure) =>
      !(failure.startsWith('blob:') && failure.endsWith('net::ERR_ABORTED'))
  );
  expect(materialFailures).toEqual([]);
  expect(runtime.pageErrors).toEqual([]);
  expect(runtime.consoleErrors).toEqual([]);
}

test.describe.serial('real ffmpeg.wasm operation matrix', () => {
  let cancellationFixture: TemporaryMediaFixture;

  test.beforeAll(() => {
    cancellationFixture = createCancellationFixture();
  });

  test.afterAll(() => {
    cancellationFixture.dispose();
  });

  test('executes conversion, structural, analysis, image, metadata, chapter and subtitle workflows in one local engine session', async ({
    page,
  }) => {
    test.setTimeout(300_000);
    page.setDefaultTimeout(15_000);
    await page.addInitScript(() => {
      Reflect.deleteProperty(globalThis, 'showSaveFilePicker');
    });
    const runtime = observeRuntime(page);
    await page.goto('/');
    await initializeSingleThread(page);

    await test.step('queues a second browser job, cancels the active job and runs the waiting job after recovery', async () => {
      const sourceName = basename(cancellationFixture.filePath);
      await mediaInput(page).setInputFiles(cancellationFixture.filePath);
      await expect(
        page
          .locator('.media-card')
          .filter({ hasText: sourceName })
          .locator('.phase--ready')
      ).toBeVisible({ timeout: 120_000 });

      await page.getByRole('button', { name: 'Convert', exact: true }).click();
      const enqueueButton = page.getByRole('button', {
        name: 'Add to queue',
      });
      await expect(enqueueButton).toBeVisible();
      await enqueueButton.click();
      await expect(page.getByText('1 waiting', { exact: true })).toBeVisible();

      const firstCancelButton = page.getByRole('button', {
        name: 'Cancel & recover',
      });
      const firstCancelElement = await firstCancelButton.elementHandle();
      await firstCancelButton.click();
      await expect
        .poll(
          () =>
            firstCancelElement?.evaluate((element) => element.isConnected) ??
            false,
          { timeout: 120_000 }
        )
        .toBe(false);
      await expect(page.getByText('1 waiting', { exact: true })).toBeHidden({
        timeout: 120_000,
      });
      const secondCancelButton = page.getByRole('button', {
        name: 'Cancel & recover',
      });
      await expect(secondCancelButton).toBeVisible({
        timeout: 120_000,
      });
      await secondCancelButton.click();
      await expect(secondCancelButton).toBeHidden({ timeout: 120_000 });
      await expect(page.getByRole('alert')).toContainText(
        'The operation was cancelled and the engine was recreated.',
        { timeout: 120_000 }
      );
      await expect(
        page
          .locator('.engine-pill')
          .filter({ hasText: 'Single-threaded compatibility mode' })
      ).toBeVisible({ timeout: 120_000 });
      await page.getByRole('button', { name: 'New', exact: true }).click();
    });

    await test.step('audio conversion and WebM remux/re-encode', async () => {
      await importMedia(page, ['tone.flac']);
      await page.getByLabel('Export preset').selectOption('audio-mp3');
      const [mp3Card] = await runForResults(
        page,
        () =>
          page.getByRole('button', { name: 'Convert', exact: true }).click(),
        ['tone-convert.mp3'],
        { verifyMedia: true }
      );
      const mp3 = await downloadResult(page, mp3Card as Locator);
      expect(probe(mp3.filePath).streams).toEqual(
        expect.arrayContaining([
          expect.objectContaining({
            codec_name: 'mp3',
            codec_type: 'audio',
          }),
        ])
      );

      await page.getByLabel('Export preset').selectOption('audio-ogg-vorbis');
      const [oggCard] = await runForResults(
        page,
        () =>
          page.getByRole('button', { name: 'Convert', exact: true }).click(),
        ['tone-convert.ogg'],
        { verifyMedia: true }
      );
      expect(
        probe((await downloadResult(page, oggCard as Locator)).filePath).streams
      ).toEqual(
        expect.arrayContaining([
          expect.objectContaining({
            codec_name: 'vorbis',
            codec_type: 'audio',
          }),
        ])
      );

      await page.getByLabel('Export preset').selectOption('audio-flac');
      const [flacCard] = await runForResults(
        page,
        () =>
          page.getByRole('button', { name: 'Convert', exact: true }).click(),
        ['tone-convert.flac'],
        { verifyMedia: true }
      );
      expect(
        probe((await downloadResult(page, flacCard as Locator)).filePath)
          .streams
      ).toEqual(
        expect.arrayContaining([
          expect.objectContaining({
            codec_name: 'flac',
            codec_type: 'audio',
          }),
        ])
      );

      await page.getByLabel('Export preset').selectOption('audio-wav-pcm');
      const [wavCard] = await runForResults(
        page,
        () =>
          page.getByRole('button', { name: 'Convert', exact: true }).click(),
        ['tone-convert.wav'],
        { verifyMedia: true }
      );
      expect(
        probe((await downloadResult(page, wavCard as Locator)).filePath).streams
      ).toEqual(
        expect.arrayContaining([
          expect.objectContaining({
            codec_name: 'pcm_s16le',
            codec_type: 'audio',
          }),
        ])
      );

      await importMedia(page, ['pattern-av.mp4']);
      await page
        .locator('.media-card')
        .filter({ hasText: 'pattern-av.mp4' })
        .click();
      await page.getByLabel('Export preset').selectOption('audio-mp3');
      await page.getByRole('checkbox', { name: /#0 · h264/u }).uncheck();
      const [extractedAudioCard] = await runForResults(
        page,
        () =>
          page.getByRole('button', { name: 'Convert', exact: true }).click(),
        ['pattern-av-convert.mp3'],
        { verifyMedia: true }
      );
      const extractedAudio = probe(
        (await downloadResult(page, extractedAudioCard as Locator)).filePath
      );
      expect(
        extractedAudio.streams?.map((stream) => stream.codec_type)
      ).toEqual(['audio']);
      expect(extractedAudio.streams?.[0]?.codec_name).toBe('mp3');

      await page
        .getByLabel('Export preset')
        .selectOption('mp4-h264-compatibility');
      await page.getByRole('checkbox', { name: /#0 · h264/u }).check();
      await page.getByRole('checkbox', { name: /#1 · aac/u }).uncheck();
      const [videoOnlyCard] = await runForResults(
        page,
        () =>
          page.getByRole('button', { name: 'Convert', exact: true }).click(),
        ['pattern-av-convert.mp4'],
        { verifyMedia: true }
      );
      const videoOnly = probe(
        (await downloadResult(page, videoOnlyCard as Locator)).filePath
      );
      expect(videoOnly.streams?.map((stream) => stream.codec_type)).toEqual([
        'video',
      ]);
      expect(videoOnly.streams?.[0]?.codec_name).toBe('h264');

      await importMedia(page, ['pattern.webm']);
      await page
        .locator('.media-card')
        .filter({ hasText: 'pattern.webm' })
        .click();
      await page.getByRole('button', { name: 'Fast remux' }).click();
      await page.getByLabel('Target container').selectOption('matroska');
      const [remuxCard] = await runForResults(
        page,
        () => page.getByRole('button', { name: 'Remux', exact: true }).click(),
        ['pattern-remux.mkv'],
        { verifyMedia: true }
      );
      const remux = await downloadResult(page, remuxCard as Locator);
      expect(probe(remux.filePath).streams).toEqual(
        expect.arrayContaining([
          expect.objectContaining({ codec_name: 'vp8', codec_type: 'video' }),
          expect.objectContaining({
            codec_name: 'vorbis',
            codec_type: 'audio',
          }),
        ])
      );

      await page.getByRole('button', { name: 'Re-encode' }).click();
      await page.getByLabel('Export preset').selectOption('webm-vp8-vorbis');
      const [webmCard] = await runForResults(
        page,
        () =>
          page.getByRole('button', { name: 'Convert', exact: true }).click(),
        ['pattern-convert.webm'],
        { verifyMedia: true }
      );
      const webm = await downloadResult(page, webmCard as Locator);
      expect(probe(webm.filePath).streams).toEqual(
        expect.arrayContaining([
          expect.objectContaining({ codec_name: 'vp8', codec_type: 'video' }),
          expect.objectContaining({
            codec_name: 'vorbis',
            codec_type: 'audio',
          }),
        ])
      );

      await importMedia(page, ['metadata.mp4']);
      await page
        .locator('.media-card')
        .filter({ hasText: 'metadata.mp4' })
        .click();
      await page.getByRole('button', { name: 'Fast remux' }).click();
      await page.getByLabel('Target container').selectOption('mp4');
      await page.getByRole('checkbox', { name: 'Remove metadata' }).check();
      const [metadataRemovalCard] = await runForResults(
        page,
        () => page.getByRole('button', { name: 'Remux', exact: true }).click(),
        ['metadata-remux.mp4'],
        { verifyMedia: true }
      );
      const metadataRemovalProbe = probe(
        (await downloadResult(page, metadataRemovalCard as Locator)).filePath
      );
      expect(metadataRemovalProbe.format?.tags?.title).toBeUndefined();
      expect(metadataRemovalProbe.format?.tags?.artist).toBeUndefined();
      expect(metadataRemovalProbe.format?.tags?.comment).toBeUndefined();
    });

    await test.step('fast and accurate trim plus fast and normalized concat', async () => {
      await page.getByRole('button', { name: 'New', exact: true }).click();
      await page.getByRole('tab', { name: 'Edit' }).click();
      await importMedia(page, ['compatible-a.mp4', 'compatible-b.mp4']);

      const selectedTimelineClip = page
        .locator('.timeline-clip')
        .filter({ hasText: 'compatible-a.mp4' });
      await selectedTimelineClip.locator('.timeline-clip__main').click();
      await selectedTimelineClip.getByLabel('In').fill('0.1');
      await selectedTimelineClip.getByLabel('Out').fill('0.8');

      const structural = page.locator('.structural-operations');
      const [fastTrimCard] = await runForResults(
        page,
        () =>
          structural.getByRole('button', { name: 'Export fast trim' }).click(),
        ['compatible-a-trim.mp4'],
        { verifyMedia: true }
      );
      expect(
        probe((await downloadResult(page, fastTrimCard as Locator)).filePath)
          .streams
      ).toEqual(
        expect.arrayContaining([
          expect.objectContaining({ codec_name: 'h264', codec_type: 'video' }),
        ])
      );

      await structural.getByLabel('Accurate re-encode').check();
      await structural
        .getByLabel('Accurate trim preset')
        .selectOption('mp4-h264-compatibility');
      const [accurateTrimCard] = await runForResults(
        page,
        () =>
          structural.getByRole('button', { name: 'Export exact trim' }).click(),
        ['compatible-a-trim.mp4'],
        { verifyMedia: true }
      );
      expect(
        probe(
          (await downloadResult(page, accurateTrimCard as Locator)).filePath
        ).streams
      ).toEqual(
        expect.arrayContaining([
          expect.objectContaining({ codec_name: 'h264', codec_type: 'video' }),
          expect.objectContaining({ codec_name: 'aac', codec_type: 'audio' }),
        ])
      );

      await expect(
        structural.getByRole('heading', {
          name: 'Fast compatibility passed',
        })
      ).toBeVisible();
      const [fastConcatCard] = await runForResults(
        page,
        () =>
          structural
            .getByRole('button', { name: 'Export fast concat' })
            .click(),
        ['compatible-a-concat.mp4'],
        { verifyMedia: true }
      );
      expect(
        probe((await downloadResult(page, fastConcatCard as Locator)).filePath)
          .streams
      ).toEqual(
        expect.arrayContaining([
          expect.objectContaining({ codec_name: 'h264', codec_type: 'video' }),
          expect.objectContaining({ codec_name: 'aac', codec_type: 'audio' }),
        ])
      );

      await structural.getByLabel('Normalized re-encode').check();
      await structural
        .getByLabel('Normalized concat preset')
        .selectOption('mp4-h264-compatibility');
      await structural.getByLabel('Insert silence').check();
      await structural.getByLabel('Reject subtitle input').check();
      const [normalizedConcatCard] = await runForResults(
        page,
        () =>
          structural
            .getByRole('button', { name: 'Export normalized concat' })
            .click(),
        ['compatible-a-concat.mp4'],
        { verifyMedia: true }
      );
      expect(
        probe(
          (await downloadResult(page, normalizedConcatCard as Locator)).filePath
        ).streams
      ).toEqual(
        expect.arrayContaining([
          expect.objectContaining({ codec_name: 'h264', codec_type: 'video' }),
          expect.objectContaining({ codec_name: 'aac', codec_type: 'audio' }),
        ])
      );

      await structural.getByLabel('Crossfade duration').fill('0.2');
      const crossfadeAction = structural.getByRole('button', {
        name: 'Export normalized concat',
      });
      if (await crossfadeAction.isEnabled()) {
        const [crossfadeCard] = await runForResults(
          page,
          () => crossfadeAction.click(),
          ['compatible-a-concat.mp4'],
          { verifyMedia: true }
        );
        const crossfadeDuration = Number(
          probe((await downloadResult(page, crossfadeCard as Locator)).filePath)
            .format?.duration
        );
        expect(crossfadeDuration).toBeGreaterThan(1.35);
        expect(crossfadeDuration).toBeLessThan(1.75);
      } else {
        await expect(
          structural.getByText(
            /required browser and FFmpeg capabilities have not been verified|filter (?:x|a)fade/iu
          )
        ).toBeVisible();
      }
    });

    const advanced = page.locator('.advanced-operations');
    await test.step('fast/accurate split and waveform/loudness analysis', async () => {
      await advanced.getByLabel('Marker time (seconds)').fill('0.5');
      await advanced.getByRole('button', { name: 'Add marker' }).click();
      await runForResults(
        page,
        () =>
          advanced.getByRole('button', { name: 'Queue 2 segments' }).click(),
        ['compatible-a-split-001.mp4', 'compatible-a-split-002.mp4'],
        { verifyMedia: true }
      );

      await advanced.getByLabel('Accurate re-encode').check();
      await advanced
        .getByLabel('Accurate split preset')
        .selectOption('mp4-h264-compatibility');
      await runForResults(
        page,
        () =>
          advanced.getByRole('button', { name: 'Queue 2 segments' }).click(),
        ['compatible-a-split-001.mp4', 'compatible-a-split-002.mp4'],
        { verifyMedia: true }
      );

      await advanced
        .getByRole('tab', { name: 'Waveform and loudness' })
        .click();
      const [waveformCard] = await runForResults(
        page,
        () =>
          advanced
            .getByRole('button', { name: 'Generate static waveform' })
            .click(),
        ['compatible-a-waveform-static.png']
      );
      expect(
        statSync((await downloadResult(page, waveformCard as Locator)).filePath)
          .size
      ).toBeGreaterThan(1_000);

      await advanced
        .getByRole('button', { name: 'Analyze peak waveform' })
        .click();
      await expect(
        page.getByRole('region', {
          name: 'Waveform editor for compatible-a.mp4',
        })
      ).toBeVisible({ timeout: 120_000 });

      await advanced.getByRole('button', { name: 'Measure EBU R128' }).click();
      await expect(page.locator('.project-notice')).toContainText('Measured', {
        timeout: 120_000,
      });
      await expect(advanced.getByText('Measured loudness')).toBeVisible();
      await advanced
        .getByLabel('Normalization preset')
        .selectOption('audio-mp3');

      const [normalizedAudioCard] = await runForResults(
        page,
        () =>
          advanced
            .getByRole('button', { name: 'Apply measured normalization' })
            .click(),
        ['compatible-a-normalize.mp3'],
        { verifyMedia: true }
      );
      expect(
        probe(
          (await downloadResult(page, normalizedAudioCard as Locator)).filePath
        ).streams
      ).toEqual(
        expect.arrayContaining([
          expect.objectContaining({ codec_name: 'mp3', codec_type: 'audio' }),
        ])
      );

      const [peakAudioCard] = await runForResults(
        page,
        () =>
          advanced
            .getByRole('button', { name: 'Apply peak normalization' })
            .click(),
        ['compatible-a-peak-normalize.mp3'],
        { verifyMedia: true }
      );
      expect(
        probe((await downloadResult(page, peakAudioCard as Locator)).filePath)
          .streams
      ).toEqual(
        expect.arrayContaining([
          expect.objectContaining({ codec_name: 'mp3', codec_type: 'audio' }),
        ])
      );
    });

    await test.step('thumbnail series and contact sheet', async () => {
      await advanced
        .getByRole('tab', { name: 'Thumbnails and contact sheets' })
        .click();
      await advanced.getByLabel('Number of frames').fill('3');
      await runForResults(
        page,
        () =>
          advanced
            .getByRole('button', { name: 'Generate thumbnail series' })
            .click(),
        [
          'compatible-a-thumbnail-001-250ms.jpg',
          'compatible-a-thumbnail-002-500ms.jpg',
          'compatible-a-thumbnail-003-750ms.jpg',
        ]
      );

      await advanced
        .getByRole('spinbutton', { name: 'Frames', exact: true })
        .fill('4');
      await advanced
        .getByRole('spinbutton', { name: 'Rows', exact: true })
        .fill('2');
      await advanced
        .getByRole('spinbutton', { name: 'Columns', exact: true })
        .fill('2');
      await advanced
        .getByRole('spinbutton', { name: /^Cell width/u })
        .fill('128');
      const [sheetCard] = await runForResults(
        page,
        () =>
          advanced
            .getByRole('button', { name: 'Generate contact sheet' })
            .click(),
        ['compatible-a-contact-sheet.jpg']
      );
      expect(
        statSync((await downloadResult(page, sheetCard as Locator)).filePath)
          .size
      ).toBeGreaterThan(500);

      await importMedia(page, ['pattern-av.mp4']);
      const patternClip = page
        .locator('.timeline-clip')
        .filter({ hasText: 'pattern-av.mp4' });
      await patternClip.locator('.timeline-clip__main').click();
      const imageSelection = advanced.getByLabel('Frame selection').first();
      const sceneOption = imageSelection.locator(
        'option[value="scene-changes"]'
      );
      if (!(await sceneOption.isDisabled())) {
        await imageSelection.selectOption('scene-changes');
        await advanced.getByLabel('Number of frames').fill('2');
        await advanced.getByLabel('Scene sensitivity threshold').fill('0.01');
        await runForResults(
          page,
          () =>
            advanced
              .getByRole('button', { name: 'Generate thumbnail series' })
              .click(),
          [
            'pattern-av-thumbnail-001-83ms.jpg',
            'pattern-av-thumbnail-002-1000ms.jpg',
          ]
        );

        const contactSelection = advanced.getByLabel('Frame selection').nth(1);
        await contactSelection.selectOption('scene-changes');
        await advanced.getByLabel('Contact-sheet scene threshold').fill('0.01');
        await advanced
          .getByRole('spinbutton', { name: 'Frames', exact: true })
          .fill('2');
        await advanced
          .getByRole('spinbutton', { name: 'Rows', exact: true })
          .fill('1');
        await advanced
          .getByRole('spinbutton', { name: 'Columns', exact: true })
          .fill('2');
        const timestampLabels = advanced.getByLabel('Timestamp labels');
        if (await timestampLabels.isEnabled()) {
          await timestampLabels.check();
          await advanced.getByLabel('Source filename label').check();
        }
        const [sceneSheetCard] = await runForResults(
          page,
          () =>
            advanced
              .getByRole('button', { name: 'Generate contact sheet' })
              .click(),
          ['pattern-av-contact-sheet.jpg']
        );
        expect(
          statSync(
            (await downloadResult(page, sceneSheetCard as Locator)).filePath
          ).size
        ).toBeGreaterThan(500);
      }

      await patternClip.getByRole('button', { name: 'Remove clip' }).click();
      await expect(patternClip).toHaveCount(0);
      await page
        .locator('.timeline-clip')
        .filter({ hasText: 'compatible-a.mp4' })
        .first()
        .locator('.timeline-clip__main')
        .click();
    });

    await test.step('single frame and a transformed timeline with audio/video fades', async () => {
      const inspector = page.locator('.inspector');
      await inspector.getByRole('tab', { name: 'Frames' }).click();
      const inspectorBody = inspector.locator('.inspector__body');
      await inspectorBody
        .getByRole('spinbutton', { name: 'Time (seconds)', exact: true })
        .fill('0.2');
      await inspectorBody
        .getByRole('spinbutton', { name: 'Width', exact: true })
        .fill('96');
      await inspectorBody
        .getByRole('combobox', { name: 'Format', exact: true })
        .selectOption('png');
      const [singleFrameCard] = await runForResults(
        page,
        () =>
          inspectorBody.getByRole('button', { name: 'Extract frame' }).click(),
        ['compatible-a-thumbnail-200ms.png']
      );
      expect(
        statSync(
          (await downloadResult(page, singleFrameCard as Locator)).filePath
        ).size
      ).toBeGreaterThan(100);

      await inspector.getByRole('tab', { name: 'Transform' }).click();
      const cropFields = inspector.locator('.crop-editor__numeric');
      await cropFields
        .getByRole('spinbutton', { name: 'X', exact: true })
        .fill('4');
      await cropFields
        .getByRole('spinbutton', { name: 'Y', exact: true })
        .fill('2');
      await cropFields
        .getByRole('spinbutton', { name: 'Width', exact: true })
        .fill('120');
      await cropFields
        .getByRole('spinbutton', { name: 'Height', exact: true })
        .fill('68');

      const resizeFields = inspector.locator('.inspector-section > .mini-grid');
      await resizeFields
        .getByRole('spinbutton', { name: 'Width', exact: true })
        .fill('96');
      await resizeFields
        .getByRole('spinbutton', { name: 'Height', exact: true })
        .fill('54');
      await resizeFields
        .getByRole('combobox', { name: 'Rotate', exact: true })
        .selectOption('90');
      await resizeFields
        .getByRole('combobox', { name: 'Scale algorithm', exact: true })
        .selectOption('bicubic');
      await resizeFields
        .getByRole('textbox', { name: 'Padding colour', exact: true })
        .fill('#112233');
      await page
        .getByRole('spinbutton', { name: 'Output frame rate', exact: true })
        .fill('12');

      const videoFades = inspector
        .locator('fieldset.subpanel')
        .filter({ hasText: 'Video fades' });
      await videoFades
        .getByRole('spinbutton', { name: 'Fade in from black (s)' })
        .fill('0.1');
      await videoFades
        .getByRole('spinbutton', { name: 'Fade out to black (s)' })
        .fill('0.1');

      await inspector.getByRole('tab', { name: 'Audio' }).click();
      await expect(
        inspectorBody.getByRole('checkbox', { name: 'Include audio' })
      ).toBeChecked();
      await inspectorBody
        .getByRole('spinbutton', { name: 'Fade in (s)', exact: true })
        .fill('0.1');
      await inspectorBody
        .getByRole('spinbutton', { name: 'Fade out (s)', exact: true })
        .fill('0.1');

      const [timelineCard] = await runForResults(
        page,
        () => page.getByRole('button', { name: 'Render timeline' }).click(),
        ['output.mp4'],
        { verifyMedia: true }
      );
      const timelineProbe = probe(
        (await downloadResult(page, timelineCard as Locator)).filePath
      );
      const timelineVideo = timelineProbe.streams?.find(
        (stream) => stream.codec_type === 'video'
      );
      expect(timelineVideo).toMatchObject({
        codec_name: 'h264',
        width: 96,
        height: 54,
        avg_frame_rate: '12/1',
      });
      expect(
        timelineProbe.streams?.some(
          (stream) =>
            stream.codec_type === 'audio' && stream.codec_name === 'aac'
        )
      ).toBe(true);
    });

    await test.step('metadata and chapters survive round-trip probing', async () => {
      await advanced.getByRole('tab', { name: 'Metadata policies' }).click();
      const metadataPanel = advanced.getByRole('tabpanel');
      await metadataPanel
        .getByRole('textbox', { name: 'Title', exact: true })
        .fill('Browser Matrix');
      await metadataPanel
        .getByRole('textbox', { name: 'Artist', exact: true })
        .fill('av-tools Playwright');
      const [metadataCard] = await runForResults(
        page,
        () =>
          advanced
            .getByRole('button', { name: 'Apply metadata policies' })
            .click(),
        ['compatible-a-metadata.mp4'],
        { verifyMedia: true }
      );
      const metadataProbe = probe(
        (await downloadResult(page, metadataCard as Locator)).filePath
      );
      expect(metadataProbe.format?.tags).toMatchObject({
        title: 'Browser Matrix',
        artist: 'av-tools Playwright',
      });

      await advanced.getByRole('tab', { name: 'Chapter execution' }).click();
      await advanced
        .getByLabel('Create output chapters from')
        .selectOption('fixed');
      await advanced.getByLabel('Chapter interval').fill('0.5');
      const [chapterCard] = await runForResults(
        page,
        () =>
          advanced
            .getByRole('button', { name: 'Replace output chapters' })
            .click(),
        ['compatible-a-chapters.mp4'],
        { verifyMedia: true }
      );
      const chapterProbe = probe(
        (await downloadResult(page, chapterCard as Locator)).filePath
      );
      expect(chapterProbe.chapters).toHaveLength(2);
      expect(
        chapterProbe.chapters?.map((chapter) => chapter.tags?.title)
      ).toEqual(['Chapter 1', 'Chapter 2']);
    });

    await test.step('subtitle convert, mux, burn-in and extraction', async () => {
      await advanced.getByRole('tab', { name: 'Subtitle operations' }).click();
      const subtitlePanel = advanced.getByRole('tabpanel');
      const subtitleOperation = subtitlePanel
        .locator('label.advanced-field')
        .filter({ hasText: /^Operation/u })
        .locator('select');
      const outputTextFormat = subtitlePanel
        .locator('label.advanced-field')
        .filter({ hasText: /^Output text format/u })
        .locator('select');
      await subtitleOperation.selectOption('convert');
      const localSubtitleInput = subtitlePanel.locator(
        'label.advanced-file-field input[type="file"]'
      );
      await markExistingResults(page);
      await localSubtitleInput.setInputFiles({
        name: 'invalid-subtitle.srt',
        mimeType: 'application/x-subrip',
        buffer: Buffer.from('this is not a timed subtitle\n'),
      });
      await subtitlePanel
        .getByRole('button', { name: 'Convert subtitle' })
        .click();
      await expect(
        advanced.locator('.advanced-operations__status')
      ).toContainText(/FFmpeg (?:exited|produced)/u, {
        timeout: 120_000,
      });
      await expect(newResultCards(page)).toHaveCount(0);
      await expect(
        page
          .locator('.engine-pill')
          .filter({ hasText: 'Single-threaded compatibility mode' })
      ).toBeVisible({ timeout: 120_000 });

      await localSubtitleInput.setInputFiles(fixture('subtitle.srt'));
      await outputTextFormat.selectOption('vtt');
      await subtitlePanel.getByLabel('Time offset').fill('0.1');
      const [convertedCard] = await runForResults(
        page,
        () =>
          subtitlePanel
            .getByRole('button', { name: 'Convert subtitle' })
            .click(),
        ['subtitle-subtitle.vtt']
      );
      const converted = await downloadResult(page, convertedCard as Locator);
      expect(readFileSync(converted.filePath, 'utf8')).toContain('WEBVTT');

      await subtitleOperation.selectOption('soft-mux');
      await subtitlePanel
        .locator('label.advanced-field')
        .filter({ hasText: /^Target container/u })
        .locator('select')
        .selectOption('matroska');
      await subtitlePanel
        .getByRole('textbox', { name: 'Language', exact: true })
        .fill('eng');
      await subtitlePanel
        .getByRole('textbox', { name: 'Track title', exact: true })
        .fill('Browser subtitle');
      await subtitlePanel
        .getByRole('checkbox', { name: 'Default track' })
        .check();
      const [muxedCard] = await runForResults(
        page,
        () =>
          subtitlePanel
            .getByRole('button', { name: 'Mux soft subtitle' })
            .click(),
        ['compatible-a-subtitled.mkv'],
        { verifyMedia: true }
      );
      const muxed = await downloadResult(page, muxedCard as Locator);
      expect(probe(muxed.filePath).streams).toEqual(
        expect.arrayContaining([
          expect.objectContaining({
            codec_name: 'subrip',
            codec_type: 'subtitle',
            tags: expect.objectContaining({
              language: 'eng',
              title: 'Browser subtitle',
            }),
            disposition: expect.objectContaining({ default: 1 }),
          }),
        ])
      );

      await subtitleOperation.selectOption('burn-in');
      await subtitlePanel
        .locator('label.advanced-field')
        .filter({ hasText: /^Video export preset/u })
        .locator('select')
        .selectOption('mp4-h264-compatibility');
      const [burnedCard] = await runForResults(
        page,
        () =>
          subtitlePanel
            .getByRole('button', { name: 'Burn subtitle into video' })
            .click(),
        ['compatible-a-subtitle-burn.mp4'],
        { verifyMedia: true }
      );
      expect(
        probe((await downloadResult(page, burnedCard as Locator)).filePath)
          .streams
      ).toEqual(
        expect.arrayContaining([
          expect.objectContaining({ codec_name: 'h264', codec_type: 'video' }),
        ])
      );

      await page.getByRole('button', { name: 'New', exact: true }).click();
      await mediaInput(page).setInputFiles({
        name: 'subtitled-source.mkv',
        mimeType: 'video/x-matroska',
        buffer: readFileSync(muxed.filePath),
      });
      await expect(
        page
          .locator('.media-card')
          .filter({ hasText: 'subtitled-source.mkv' })
          .locator('.phase--ready')
      ).toBeVisible({ timeout: 120_000 });
      await subtitleOperation.selectOption('extract');
      await outputTextFormat.selectOption('srt');
      const [extractedCard] = await runForResults(
        page,
        () =>
          subtitlePanel
            .getByRole('button', { name: 'Extract subtitle' })
            .click(),
        ['subtitled-source-subtitle-eng.srt']
      );
      const extracted = await downloadResult(page, extractedCard as Locator);
      expect(readFileSync(extracted.filePath, 'utf8')).toContain(
        'Generated subtitle'
      );
    });

    expect(
      runtime.requests.some((url) =>
        url.endsWith(
          '/vendor/ffmpeg/0.12.10-reviewed-stack5m.1/st/ffmpeg-core.wasm'
        )
      )
    ).toBe(true);
    assertLocalOnly(runtime);
  });
});
