import { describe, expect, it } from 'vitest';

import {
  assessBrowserPlayback,
  assessGeneratedResultPreview,
  buildPlaybackMimeCandidates,
} from '../../../src/media/browser-playback';
import type {
  MediaProbe,
  MediaStreamProbe,
} from '../../../src/media/media.types';
import {
  selectDefaultStreams,
  streamSelectionMapArgs,
  validateStreamSelection,
} from '../../../src/media/stream-selection';

function stream(
  index: number,
  type: MediaStreamProbe['type'],
  overrides: Partial<MediaStreamProbe> = {}
): MediaStreamProbe {
  return {
    index,
    type,
    disposition: {},
    tags: {},
    ...overrides,
  };
}

function probe(streams: MediaStreamProbe[]): MediaProbe {
  return {
    formatNames: ['mov', 'mp4'],
    tags: {},
    streams,
    chapters: [],
    warnings: [],
  };
}

describe('stream selection', () => {
  const media = probe([
    stream(0, 'video', { codecName: 'h264' }),
    stream(1, 'audio', {
      language: 'eng',
      disposition: { default: true },
    }),
    stream(2, 'audio', {
      language: 'de-DE',
    }),
    stream(3, 'subtitle', { language: 'deu' }),
    stream(4, 'video', { disposition: { attached_pic: true } }),
  ]);

  it('chooses default streams, avoids cover art and can include subtitles', () => {
    expect(
      selectDefaultStreams(media, {
        preferredAudioLanguages: ['de'],
        preferredSubtitleLanguages: ['deu'],
        includeSubtitles: true,
      })
    ).toEqual({
      videoStreamIndex: 0,
      audioStreamIndexes: [2],
      subtitleStreamIndexes: [3],
    });
  });

  it('validates stream existence, type and duplicate mappings', () => {
    const result = validateStreamSelection(media, {
      videoStreamIndex: 1,
      audioStreamIndexes: [2, 2, 99],
      subtitleStreamIndexes: [],
    });
    expect(result.valid).toBe(false);
    expect(result.issues.map((issue) => issue.code)).toEqual([
      'wrong-stream-type',
      'duplicate-stream',
      'stream-not-found',
    ]);
  });

  it('generates structured map arguments in deterministic order', () => {
    expect(
      streamSelectionMapArgs({
        videoStreamIndex: 0,
        audioStreamIndexes: [2],
        subtitleStreamIndexes: [3],
      })
    ).toEqual(['-map', '0:0', '-map', '0:2', '-map', '0:3']);
  });
});

describe('browser playback assessment', () => {
  const mp4 = probe([
    stream(0, 'video', { codecName: 'h264' }),
    stream(1, 'audio', { codecName: 'aac' }),
  ]);

  it('builds codec-qualified and container-only MIME candidates', () => {
    expect(buildPlaybackMimeCandidates(mp4)).toEqual([
      'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
      'video/mp4',
    ]);
  });

  it('keeps browser support separate from FFmpeg readability', () => {
    expect(
      assessBrowserPlayback(mp4, (mime) =>
        mime.includes('codecs') ? 'probably' : ''
      )
    ).toMatchObject({
      support: 'probably',
      needsPreviewProxy: false,
    });
    expect(assessBrowserPlayback(mp4, () => '')).toMatchObject({
      support: 'unsupported',
      needsPreviewProxy: true,
    });
  });

  it('does not treat an audio/video MIME prefix as playable when the browser rejects it', () => {
    expect(
      assessGeneratedResultPreview(
        {
          fileName: 'generated.flac',
          mimeType: 'audio/flac',
        },
        () => ''
      )
    ).toMatchObject({
      kind: 'audio',
      previewable: false,
      support: 'unsupported',
    });
    expect(
      assessGeneratedResultPreview(
        {
          fileName: 'generated.mp4',
          mimeType: 'video/mp4',
          probe: mp4,
        },
        (mime) => (mime.includes('codecs') ? 'probably' : '')
      )
    ).toMatchObject({
      kind: 'video',
      previewable: true,
      support: 'probably',
    });
    expect(
      assessGeneratedResultPreview(
        {
          fileName: 'frame.png',
          mimeType: 'image/png',
        },
        () => ''
      )
    ).toMatchObject({ kind: 'image', previewable: true });
    expect(
      assessGeneratedResultPreview(
        {
          fileName: 'frame.tiff',
          mimeType: 'image/tiff',
        },
        () => ''
      )
    ).toMatchObject({
      kind: 'image',
      previewable: false,
      support: 'unsupported',
    });
  });
});
