/**
 * A Jellyfin DeviceProfile describing what this browser client can play.
 *
 * The server uses this to decide direct-play vs direct-stream vs transcode
 * and to choose codecs/containers that browsers can decode.
 *
 * Strategy mirrors jellyfin-web:
 *   - DirectPlay any mp4/m4v with codecs the browser advertises support for.
 *   - Transcode (or stream-copy via remux) into fMP4 over HLS, served through
 *     hls.js + MSE. Listing multiple VideoCodec values on the TranscodingProfile
 *     lets the server pick the source codec when it's already compatible -
 *     that's the difference between "remux a file in 2 seconds" and "re-encode
 *     every frame in real time". A Raspberry Pi can do the former; nothing in
 *     this codebase makes it do the latter unless the source is genuinely
 *     incompatible.
 *
 * MaxStreamingBitrate is intentionally high - we'd rather direct-stream the
 * source bitrate as-is than throttle it. The server only honours the cap when
 * a transcode is actually required.
 */

/**
 * Best-effort runtime probes for codec support in MSE. Browsers report this
 * accurately for VP9/AV1; HEVC support is hardware-gated and can vary even
 * on the same browser version, so we trust whatever isTypeSupported says.
 */
function canPlayInMse(mime: string): boolean {
  try {
    return typeof MediaSource !== 'undefined' && MediaSource.isTypeSupported(mime)
  } catch {
    return false
  }
}

async function canDecodeHdr(contentType: string, transferFunction: 'pq' | 'hlg' = 'pq'): Promise<boolean> {
  if (!canPlayInMse(contentType)) return false
  if (typeof navigator.mediaCapabilities?.decodingInfo !== 'function') return false

  try {
    const info = await navigator.mediaCapabilities.decodingInfo({
      type: 'media-source',
      video: {
        contentType,
        width: 3840,
        height: 2160,
        bitrate: 25_000_000,
        framerate: 24,
        colorGamut: 'rec2020',
        transferFunction,
      },
    } as any)
    return !!info.supported
  } catch {
    return false
  }
}

function supportedVideoCodecs(): string[] {
  const codecs: string[] = ['h264']
  // HEVC main profile level 5.1 - the spec ceiling for 4K consumer
  // hardware. Bumping the probe to 5.1 makes 4K HEVC SDR/HDR content
  // direct-play on Chromium + WebView2 when the OS has the HEVC codec
  // installed. Older 3.0 probes rejected perfectly valid 4K rips and
  // forced the server to transcode.
  if (canPlayInMse('video/mp4; codecs="hev1.1.6.L153.B0"') ||
      canPlayInMse('video/mp4; codecs="hvc1.1.6.L153.B0"')) {
    codecs.push('hevc')
  }
  if (canPlayInMse('video/mp4; codecs="vp09.00.10.08"')) {
    codecs.push('vp9')
  }
  if (canPlayInMse('video/mp4; codecs="av01.0.04M.08"')) {
    codecs.push('av1')
  }
  return codecs
}

/**
 * Check whether the display is in HDR mode. On Windows this means the
 * user has "Use HDR" turned on in Display Settings. The media query
 * returns false on SDR-only panels and on HDR panels with HDR mode off.
 *
 * jellyfin-web uses browser-identification heuristics (hardcoding
 * `browser.chrome && !browser.mobile` etc.) because it doesn't control
 * the shell. We control the Tauri shell so we can use the actual media
 * query - same outcome, fewer moving parts.
 */
function displaySupportsHdr(): boolean {
  try {
    return window.matchMedia('(dynamic-range: high)').matches
  } catch {
    return false
  }
}

/**
 * HDR format detection. Two-stage gate:
 *   1. Codec probe - does the browser's MSE stack understand the codec
 *      string for this HDR format?
 *   2. Display check - is the user's display actually in HDR mode?
 *
 * Both must be true. Advertising HDR10/HLG/DOVI in VideoRangeType when
 * the display is SDR causes the server to direct-play the file; the
 * browser then tone-maps it to SDR, which works but bypasses the
 * server's configurable FFmpeg tone-mapping and can produce different
 * (often worse) results.
 *
 * Codec strings probed:
 *   - HDR10 / HDR10+ / HLG: HEVC main10 level 5.1 (`hvc1.2.4.L153.B0`)
 *     or VP9.2 (`vp09.02.10.10.01.09.16.09.00`)
 *   - Dolby Vision: `dvh1.05.06` / `dvhe.05.06`
 */
async function supportedVideoRanges(): Promise<string> {
  const ranges = ['SDR']
  if (!displaySupportsHdr()) return ranges.join('|')

  const hdrCodec = (await Promise.all([
    canDecodeHdr('video/mp4; codecs="hvc1.2.4.L153.B0"'),
    canDecodeHdr('video/mp4; codecs="hev1.2.4.L153.B0"'),
    canDecodeHdr('video/mp4; codecs="av01.0.08M.10.0.110.09"'),
    canDecodeHdr('video/webm; codecs="vp09.02.10.10.01.09.16.09.00"'),
  ])).some(Boolean)
  if (hdrCodec) {
    ranges.push('HDR10', 'HDR10Plus')
  }

  const hlgCodec = (await Promise.all([
    canDecodeHdr('video/mp4; codecs="hvc1.2.4.L153.B0"', 'hlg'),
    canDecodeHdr('video/mp4; codecs="hev1.2.4.L153.B0"', 'hlg'),
    canDecodeHdr('video/mp4; codecs="av01.0.08M.10.0.110.09"', 'hlg'),
    canDecodeHdr('video/webm; codecs="vp09.02.10.10.01.09.16.09.00"', 'hlg'),
  ])).some(Boolean)
  if (hlgCodec && !ranges.includes('HLG')) ranges.push('HLG')

  const dvCodec = (await Promise.all([
    canDecodeHdr('video/mp4; codecs="dvh1.05.06"'),
    canDecodeHdr('video/mp4; codecs="dvhe.05.06"'),
  ])).some(Boolean)
  if (dvCodec) {
    ranges.push('DOVI', 'DOVIWithHDR10', 'DOVIWithHLG', 'DOVIWithSDR')
  }
  return ranges.join('|')
}

/**
 * Exported helper so StreamInfo and other diagnostics can show whether
 * the display is in HDR mode without re-probing the codec strings.
 */
export function isHdrDisplayActive(): boolean {
  return displaySupportsHdr()
}

export async function browserDeviceProfile(audioPassthrough = false) {
  const videoCodecs = supportedVideoCodecs()
  const videoCodecsCsv = videoCodecs.join(',')
  const videoRanges = await supportedVideoRanges()

  return {
    Name: 'Jellybloom Browser Client',
    MaxStreamingBitrate: 120_000_000,
    MaxStaticBitrate: 100_000_000,
    MusicStreamingTranscodingBitrate: 384_000,

    DirectPlayProfiles: [
      {
        // Chromium can natively play mp4/m4v. Everything else (mkv, avi, etc)
        // goes through the HLS TranscodingProfile below, which remuxes into
        // fMP4 that hls.js + MSE can handle. Listing mkv here would make the
        // server return SupportsDirectPlay=true, but Chromium's <video> can't
        // actually decode raw MKV - the player would just stall.
        Container: 'mp4,m4v',
        Type: 'Video',
        VideoCodec: videoCodecsCsv,
        AudioCodec: audioPassthrough
          ? 'aac,mp3,ac3,eac3,flac,opus,truehd,dts,alac,wmapro'
          : 'aac,mp3,ac3,eac3,flac,opus',
      },
      {
        Container: 'webm',
        Type: 'Video',
        VideoCodec: 'vp8,vp9,av1',
        AudioCodec: 'opus,vorbis',
      },
    ],

    TranscodingProfiles: [
      {
        // fMP4 over HLS. Listing the full supported codec set lets the server
        // stream-copy (remux only) when the source already matches one of
        // them - that's what makes h264-in-mkv "play instantly" instead of
        // burning CPU. The browser plays this through MSE via hls.js.
        Container: 'mp4',
        Type: 'Video',
        VideoCodec: videoCodecsCsv,
        AudioCodec: 'aac,mp3',
        Protocol: 'hls',
        Context: 'Streaming',
        MaxAudioChannels: '6',
        MinSegments: 1,
        BreakOnNonKeyFrames: true,
      },
      {
        Container: 'aac',
        Type: 'Audio',
        AudioCodec: 'aac',
        Context: 'Streaming',
        Protocol: 'http',
        MaxAudioChannels: '2',
      },
    ],

    ContainerProfiles: [],
    CodecProfiles: [
      // Bound h264 to profiles/levels MSE actually decodes - avoids the
      // server stream-copying high-10 or level 5.2 footage that the browser
      // would silently refuse.
      {
        Type: 'Video',
        Codec: 'h264',
        Conditions: [
          {
            Condition: 'EqualsAny',
            Property: 'VideoProfile',
            Value: 'high|main|baseline|constrained baseline|high 10',
            IsRequired: false,
          },
          {
            Condition: 'LessThanEqual',
            Property: 'VideoLevel',
            Value: '52',
            IsRequired: false,
          },
        ],
      },
      // HEVC: cap at main / main10 + level 5.1 - matches what hardware
      // decoders on most consumer GPUs can chew through. VideoRangeType
      // only advertises HDR when the display is actually in HDR mode, so
      // the server does FFmpeg tone-mapping for SDR displays instead of
      // relying on the browser's built-in tone-mapping.
      {
        Type: 'Video',
        Codec: 'hevc',
        Conditions: [
          {
            Condition: 'EqualsAny',
            Property: 'VideoProfile',
            Value: 'main|main 10',
            IsRequired: false,
          },
          {
            Condition: 'LessThanEqual',
            Property: 'VideoLevel',
            Value: '153',
            IsRequired: false,
          },
          {
            Condition: 'EqualsAny',
            Property: 'VideoRangeType',
            Value: videoRanges,
            IsRequired: true,
          },
        ],
      },
      // VP9 + AV1 also support HDR transport; advertise the same range
      // matrix so 4K HDR YouTube-style sources direct-play.
      {
        Type: 'Video',
        Codec: 'vp9',
        Conditions: [
          {
            Condition: 'EqualsAny',
            Property: 'VideoRangeType',
            Value: videoRanges,
            IsRequired: true,
          },
        ],
      },
      {
        Type: 'Video',
        Codec: 'av1',
        Conditions: [
          {
            Condition: 'EqualsAny',
            Property: 'VideoRangeType',
            Value: videoRanges,
            IsRequired: true,
          },
        ],
      },
    ],

    // Mirror jellyfin-web: only External delivery. The server decides
    // whether to burn-in or deliver externally based on these profiles.
    // With no Embed/Hls methods listed, the server won't try to mux
    // subtitles into the transcode stream - it delivers them as separate
    // files that the client loads via libass-wasm or native VTT tracks.
    SubtitleProfiles: [
      { Format: 'vtt', Method: 'External' },
      { Format: 'ass', Method: 'External' },
      { Format: 'ssa', Method: 'External' },
      { Format: 'subrip', Method: 'External' },
    ],

    ResponseProfiles: [],
  }
}
