import {
  AacProfile,
  ColorMatrix,
  ColorPrimaries,
  ColorTransfer,
  DvProfile,
  DvSignalCompatibility,
  H264Profile,
  HevcProfile,
} from 'src/enum';
import { AudioStreamInfo, VideoFormat, VideoInfo, VideoStreamInfo } from 'src/types';

const probeStubDefaultFormat: VideoFormat = {
  formatName: 'mov,mp4,m4a,3gp,3g2,mj2',
  formatLongName: 'QuickTime / MOV',
  duration: 0,
  bitrate: 0,
};

const probeStubDefaultVideoStream: VideoStreamInfo[] = [
  {
    index: 0,
    height: 1080,
    width: 1920,
    codecName: 'hevc',
    frameCount: 100,
    rotation: 0,
    bitrate: 0,
    colorPrimaries: ColorPrimaries.Bt709,
    colorTransfer: ColorTransfer.Bt709,
    colorMatrix: ColorMatrix.Bt709,
    pixelFormat: 'yuv420p',
    frameRate: 60,
    timeBase: 600,
    profile: HevcProfile.Main,
    level: null,
    dvBlSignalCompatibilityId: null,
    dvLevel: null,
    dvProfile: null,
  },
];

const probeStubDefaultAudioStream: AudioStreamInfo[] = [{ index: 3, codecName: 'mp3', bitrate: 100, profile: null }];

const probeStubDefault: VideoInfo = {
  format: probeStubDefaultFormat,
  videoStreams: probeStubDefaultVideoStream,
  audioStreams: probeStubDefaultAudioStream,
};

/** Fixtures in the shape `mediaRepository.probe()` returns (arrays of streams, raw ffprobe format). */
export const videoInfoStub = {
  noVideoStreams: Object.freeze<VideoInfo>({ ...probeStubDefault, videoStreams: [] }),
  noAudioStreams: Object.freeze<VideoInfo>({ ...probeStubDefault, audioStreams: [] }),
  multipleVideoStreams: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 1,
        height: 1080,
        width: 400,
        codecName: 'hevc',
        frameCount: 2,
        rotation: 0,
        bitrate: 101,
        colorPrimaries: ColorPrimaries.Bt709,
        colorTransfer: ColorTransfer.Bt709,
        colorMatrix: ColorMatrix.Bt709,
        pixelFormat: 'yuv420p',
        frameRate: 60,
        timeBase: 600,
        profile: HevcProfile.Main,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
      {
        index: 0,
        height: 1080,
        width: 400,
        codecName: 'hevc',
        frameCount: 1,
        rotation: 0,
        bitrate: 100,
        colorPrimaries: ColorPrimaries.Bt709,
        colorTransfer: ColorTransfer.Bt709,
        colorMatrix: ColorMatrix.Bt709,
        pixelFormat: 'yuv420p',
        frameRate: 60,
        timeBase: 600,
        profile: HevcProfile.Main,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
      {
        index: 2,
        height: 1080,
        width: 400,
        codecName: 'h7000',
        frameCount: 3,
        rotation: 0,
        bitrate: 99,
        colorPrimaries: ColorPrimaries.Bt709,
        colorTransfer: ColorTransfer.Bt709,
        colorMatrix: ColorMatrix.Bt709,
        pixelFormat: 'yuv420p',
        frameRate: 60,
        timeBase: 600,
        profile: HevcProfile.Main,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
    ],
  }),
  multipleAudioStreams: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    audioStreams: [
      { index: 2, codecName: 'mp3', bitrate: 102, profile: null },
      { index: 1, codecName: 'mp3', bitrate: 101, profile: null },
      { index: 0, codecName: 'mp3', bitrate: 100, profile: null },
    ],
  }),
  noHeight: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 0,
        height: 0,
        width: 400,
        codecName: 'hevc',
        frameCount: 100,
        rotation: 0,
        bitrate: 0,
        colorPrimaries: ColorPrimaries.Bt709,
        colorTransfer: ColorTransfer.Bt709,
        colorMatrix: ColorMatrix.Bt709,
        pixelFormat: 'yuv420p',
        frameRate: 60,
        timeBase: 600,
        profile: HevcProfile.Main,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
    ],
  }),
  videoStream2160p: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 0,
        height: 2160,
        width: 3840,
        codecName: 'h264',
        frameCount: 100,
        rotation: 0,
        bitrate: 0,
        colorPrimaries: ColorPrimaries.Bt709,
        colorTransfer: ColorTransfer.Bt709,
        colorMatrix: ColorMatrix.Bt709,
        pixelFormat: 'yuv420p',
        frameRate: 60,
        timeBase: 600,
        profile: HevcProfile.Main,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
    ],
  }),
  videoStream40Mbps: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [{ ...probeStubDefaultVideoStream[0], bitrate: 40_000_000, codecName: 'h264' }],
  }),
  videoStreamMTS: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    format: {
      formatName: 'mpegts',
      formatLongName: 'MPEG-TS (MPEG-2 Transport Stream)',
      duration: 0,
      bitrate: 0,
    },
  }),
  videoStreamHDR: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 0,
        height: 480,
        width: 480,
        codecName: 'h264',
        frameCount: 100,
        rotation: 0,
        colorPrimaries: ColorPrimaries.Bt2020,
        colorMatrix: ColorMatrix.Bt2020Nc,
        colorTransfer: ColorTransfer.Smpte2084,
        bitrate: 0,
        pixelFormat: 'yuv420p10le',
        frameRate: 60,
        timeBase: 600,
        profile: H264Profile.High10,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
    ],
  }),
  videoStream10Bit: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 0,
        height: 480,
        width: 480,
        codecName: 'h264',
        frameCount: 100,
        rotation: 0,
        bitrate: 0,
        colorPrimaries: ColorPrimaries.Bt709,
        colorTransfer: ColorTransfer.Bt709,
        colorMatrix: ColorMatrix.Bt709,
        pixelFormat: 'yuv420p10le',
        frameRate: 60,
        timeBase: 600,
        profile: H264Profile.High10,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
    ],
  }),
  videoStream4K10Bit: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 0,
        height: 2160,
        width: 3840,
        codecName: 'h264',
        frameCount: 100,
        rotation: 0,
        bitrate: 0,
        colorPrimaries: ColorPrimaries.Bt709,
        colorTransfer: ColorTransfer.Bt709,
        colorMatrix: ColorMatrix.Bt709,
        pixelFormat: 'yuv420p10le',
        frameRate: 60,
        timeBase: 600,
        profile: H264Profile.High10,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
    ],
  }),
  videoStreamVertical2160p: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 0,
        height: 2160,
        width: 3840,
        codecName: 'h264',
        frameCount: 100,
        rotation: 90,
        bitrate: 0,
        colorPrimaries: ColorPrimaries.Bt709,
        colorTransfer: ColorTransfer.Bt709,
        colorMatrix: ColorMatrix.Bt709,
        pixelFormat: 'yuv420p',
        frameRate: 60,
        timeBase: 600,
        profile: H264Profile.High,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
    ],
  }),
  videoStreamOddHeight: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 0,
        height: 355,
        width: 1586,
        codecName: 'h264',
        frameCount: 100,
        rotation: 0,
        bitrate: 0,
        colorPrimaries: ColorPrimaries.Bt709,
        colorTransfer: ColorTransfer.Bt709,
        colorMatrix: ColorMatrix.Bt709,
        pixelFormat: 'yuv420p',
        frameRate: 60,
        timeBase: 600,
        profile: H264Profile.Main,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
    ],
  }),
  videoStreamOddWidth: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 0,
        height: 1586,
        width: 355,
        codecName: 'h264',
        frameCount: 100,
        rotation: 0,
        bitrate: 0,
        colorPrimaries: ColorPrimaries.Bt709,
        colorTransfer: ColorTransfer.Bt709,
        colorMatrix: ColorMatrix.Bt709,
        pixelFormat: 'yuv420p',
        frameRate: 60,
        timeBase: 600,
        profile: H264Profile.Main,
        level: null,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
    ],
  }),
  audioStreamAac: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    audioStreams: [{ index: 1, codecName: 'aac', bitrate: 100, profile: AacProfile.Lc }],
  }),
  audioStreamMp3: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    audioStreams: [{ index: 1, codecName: 'mp3', bitrate: 100, profile: null }],
  }),
  audioStreamOpus: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    audioStreams: [{ index: 1, codecName: 'opus', bitrate: 100, profile: null }],
  }),
  audioStreamUnknown: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    audioStreams: [
      { index: 0, codecName: 'aac', bitrate: 100, profile: AacProfile.Lc },
      { index: 1, codecName: 'unknown', bitrate: 200, profile: null },
    ],
  }),
  matroskaContainer: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    format: {
      formatName: 'matroska,webm',
      formatLongName: 'Matroska / WebM',
      duration: 0,
      bitrate: 0,
    },
  }),
  videoStreamVp9: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [{ ...probeStubDefaultVideoStream[0], codecName: 'vp9' }],
    format: {
      formatName: 'matroska,webm',
      formatLongName: 'Matroska / WebM',
      duration: 0,
      bitrate: 0,
    },
  }),
  videoStreamH264: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [{ ...probeStubDefaultVideoStream[0], codecName: 'h264' }],
  }),
  videoStreamAvi: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [{ ...probeStubDefaultVideoStream[0], codecName: 'h264' }],
    format: {
      formatName: 'avi',
      formatLongName: 'AVI (Audio Video Interleaved)',
      duration: 0,
      bitrate: 0,
    },
  }),
  videoStreamReserved: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        ...probeStubDefaultVideoStream[0],
        colorPrimaries: ColorPrimaries.Reserved,
        colorMatrix: ColorMatrix.Reserved,
        colorTransfer: ColorTransfer.Reserved,
      },
    ],
  }),
  videoStreamHDR10: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 0,
        height: 2160,
        width: 3840,
        codecName: 'hevc',
        profile: 2,
        level: 153,
        frameCount: 1208,
        frameRate: 59.94,
        rotation: 0,
        bitrate: 64_000_000,
        pixelFormat: 'yuv420p10le',
        colorPrimaries: ColorPrimaries.Bt2020,
        colorMatrix: ColorMatrix.Bt2020Nc,
        colorTransfer: ColorTransfer.Smpte2084,
        timeBase: 600,
        dvBlSignalCompatibilityId: null,
        dvLevel: null,
        dvProfile: null,
      },
    ],
  }),
  videoStreamDolbyVision: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        index: 0,
        height: 2160,
        width: 3840,
        codecName: 'hevc',
        profile: 2,
        level: 153,
        frameCount: 1299,
        frameRate: 59.94,
        rotation: 0,
        bitrate: 53_500_000,
        pixelFormat: 'yuv420p10le',
        colorPrimaries: ColorPrimaries.Bt2020,
        colorMatrix: ColorMatrix.Bt2020Nc,
        colorTransfer: ColorTransfer.AribStdB67,
        dvProfile: DvProfile.Dvhe08,
        dvLevel: 10,
        dvBlSignalCompatibilityId: DvSignalCompatibility.Hlg,
        timeBase: 600,
      },
    ],
  }),
  videoStreamWithProfileLevel: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    videoStreams: [
      {
        ...probeStubDefaultVideoStream[0],
        codecName: 'h264',
        profile: 100,
        level: 40,
      },
    ],
  }),
  audioStreamAAC: Object.freeze<VideoInfo>({
    ...probeStubDefault,
    audioStreams: [
      {
        index: 1,
        codecName: 'aac',
        profile: 2,
        bitrate: 128_000,
      },
    ],
  }),
};

interface SelectedStreams {
  videoStream: VideoStreamInfo & { timeBase: number };
  audioStream: AudioStreamInfo | null;
  format: VideoFormat;
}

const toSelectedStreams = (info: VideoInfo) => ({
  videoStream: info.videoStreams[0] ?? null,
  audioStream: info.audioStreams[0] ?? null,
  format: info.format,
});

export const probeStub = Object.fromEntries(
  Object.entries(videoInfoStub).map(([key, info]) => [key, toSelectedStreams(info)]),
) as Record<keyof typeof videoInfoStub, SelectedStreams>;

export const eiffelTower = {
  originalPath: 'eiffel-tower.mp4',
  videoStream: {
    index: 0,
    width: 1080,
    height: 1920,
    rotation: 0,
    codecName: 'h264',
    profile: H264Profile.High,
    level: 40,
    frameCount: 557,
    frameRate: 24.908_004_845_459_07,
    timeBase: 90_000,
    bitrate: 5_128_622,
    pixelFormat: 'yuv420p',
    colorPrimaries: ColorPrimaries.Smpte170M,
    colorTransfer: ColorTransfer.Smpte170M,
    colorMatrix: ColorMatrix.Smpte170M,
    dvProfile: null,
    dvLevel: null,
    dvBlSignalCompatibilityId: null,
  },
  audioStream: { codecName: 'aac', bitrate: 125_629, index: 1, profile: AacProfile.Lc },
  packets: {
    totalDuration: 2_012_441,
    packetCount: 557,
    outputFrames: 557,
    keyframePts: [0, 462_502, 925_004, 1_210_454, 1_387_506, 1_542_878, 1_850_008],
    keyframeAccDuration: [3613, 466_077, 928_541, 1_213_968, 1_391_005, 1_546_364, 1_853_469],
    keyframeOwnDuration: [3613, 3613, 3613, 3613, 3613, 3613, 3613],
  },
  format: {
    formatName: 'mov,mp4,m4a,3gp,3g2,mj2',
    formatLongName: 'QuickTime / MOV',
    duration: 22_616,
    bitrate: 5_128_622,
  },
};

export const waterfall = {
  originalPath: 'waterfall.mp4',
  videoStream: {
    index: 2,
    width: 3840,
    height: 2160,
    rotation: -90,
    codecName: 'hevc',
    profile: HevcProfile.Main,
    level: 156,
    frameCount: 309,
    frameRate: 29.829_901_982_867_92,
    timeBase: 90_000,
    bitrate: 43_363_499,
    pixelFormat: 'yuvj420p',
    colorPrimaries: ColorPrimaries.Bt709,
    colorTransfer: ColorTransfer.Bt709,
    colorMatrix: ColorMatrix.Bt709,
    dvProfile: null,
    dvLevel: null,
    dvBlSignalCompatibilityId: null,
  },
  audioStream: { codecName: 'aac', bitrate: 191_878, index: 1, profile: null },
  packets: {
    totalDuration: 932_286,
    packetCount: 309,
    outputFrames: 309,
    keyframePts: [0, 89_987, 179_974, 269_961, 359_948, 449_936, 539_923, 629_910, 725_166, 815_273, 905_295],
    keyframeAccDuration: [
      2999, 92_987, 182_974, 272_961, 362_948, 452_934, 542_922, 632_909, 728_175, 818_274, 908_296,
    ],
    keyframeOwnDuration: [2999, 3000, 3000, 3000, 3000, 2998, 2999, 2999, 3009, 3001, 3001],
  },
  format: {
    formatName: 'mov,mp4,m4a,3gp,3g2,mj2',
    formatLongName: 'QuickTime / MOV',
    duration: 10_359,
    bitrate: 43_363_499,
  },
};

export const train = {
  originalPath: 'train.mov',
  videoStream: {
    index: 0,
    width: 1920,
    height: 1080,
    rotation: -90,
    codecName: 'hevc',
    profile: HevcProfile.Main10,
    level: 123,
    frameCount: 1229,
    frameRate: 56.536_072_989_342_94,
    timeBase: 600,
    bitrate: 12_595_191,
    pixelFormat: 'yuv420p10le',
    colorPrimaries: ColorPrimaries.Bt2020,
    colorTransfer: ColorTransfer.AribStdB67,
    colorMatrix: ColorMatrix.Bt2020Nc,
    dvProfile: DvProfile.Dvhe08,
    dvLevel: 5,
    dvBlSignalCompatibilityId: DvSignalCompatibility.Hlg,
  },
  audioStream: { codecName: 'aac', bitrate: 175_477, index: 1, profile: AacProfile.Lc },
  packets: {
    totalDuration: 12_290,
    packetCount: 1229,
    outputFrames: 1304,
    keyframePts: [
      0, 601, 1201, 1802, 2402, 3003, 3604, 4204, 4805, 5405, 6006, 6607, 7207, 7808, 8408, 9009, 9609, 10_210, 10_811,
      11_411, 12_062, 12_703,
    ],
    keyframeAccDuration: [
      10, 580, 1180, 1780, 2380, 2980, 3580, 4180, 4780, 5380, 5980, 6580, 7180, 7780, 8380, 8980, 9580, 10_180, 10_780,
      11_380, 11_780, 12_100,
    ],
    keyframeOwnDuration: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10],
  },
  format: {
    formatName: 'mov,mp4,m4a,3gp,3g2,mj2',
    formatLongName: 'QuickTime / MOV',
    duration: 21_738,
    bitrate: 12_595_191,
  },
};
