import '../contracts/library.dart';
import '../../shared/utils/app_logger.dart';
import 'media_range_detector.dart';

enum VideoRangeCategory { dolbyVision, hdr10, hlg, sdr, unknown }

class MediaCapability {
  final VideoRangeCategory rangeCategory;
  final String? codec;

  const MediaCapability({required this.rangeCategory, this.codec});
}

class ProbeResult {
  final String? videoCodec;
  final String? videoRange;
  final String? videoRangeType;

  const ProbeResult({this.videoCodec, this.videoRange, this.videoRangeType});
}

class MediaCapabilityAnalyzer {
  static const _tag = 'MediaCap';

  static MediaCapability analyze(
    EmbyRawMediaSource? source, {
    ProbeResult? probeResult,
  }) {
    if (source == null && probeResult == null) {
      AppLogger.debug(_tag, 'analyze: source=null probeResult=null -> unknown');
      return const MediaCapability(rangeCategory: VideoRangeCategory.unknown);
    }

    final codec = _resolveCodec(source, probeResult);
    final videoRange = _resolveVideoRange(source, probeResult);
    final videoRangeType = _resolveVideoRangeType(source, probeResult);

    final isDV = _checkDolbyVision(
      source,
      probeResult,
      codec,
      videoRange,
      videoRangeType,
    );
    final isHdrDetected = _checkHdr(
      source,
      probeResult,
      videoRange,
      videoRangeType,
    );

    final VideoRangeCategory rangeCategory;
    if (isDV) {
      rangeCategory = VideoRangeCategory.dolbyVision;
    } else if (isHdrDetected) {
      rangeCategory = _classifyHdr(videoRangeType, videoRange);
    } else {
      rangeCategory = VideoRangeCategory.sdr;
    }

    AppLogger.debug(
      _tag,
      'analyze: codec=$codec '
      'videoRange=$videoRange videoRangeType=$videoRangeType '
      '-> rangeCategory=${rangeCategory.name}',
    );

    return MediaCapability(rangeCategory: rangeCategory, codec: codec);
  }

  static String? _resolveCodec(EmbyRawMediaSource? source, ProbeResult? probe) {
    if (probe?.videoCodec != null) return probe!.videoCodec;
    if (source == null) return null;
    final video = findVideoStream(source);
    return video?.Codec;
  }

  static String? _resolveVideoRange(
    EmbyRawMediaSource? source,
    ProbeResult? probe,
  ) {
    if (probe?.videoRange != null) return probe!.videoRange;
    if (source == null) return null;
    final video = findVideoStream(source);
    return video?.extra['VideoRange'] as String?;
  }

  static String? _resolveVideoRangeType(
    EmbyRawMediaSource? source,
    ProbeResult? probe,
  ) {
    if (probe?.videoRangeType != null) return probe!.videoRangeType;
    if (source == null) return null;
    final video = findVideoStream(source);
    return video?.extra['VideoRangeType'] as String?;
  }

  static bool _checkDolbyVision(
    EmbyRawMediaSource? source,
    ProbeResult? probe,
    String? codec,
    String? videoRange,
    String? videoRangeType,
  ) {
    if (probe != null) {
      final lCodec = codec?.toLowerCase() ?? '';
      final lRange = videoRange?.toLowerCase() ?? '';
      final lRangeType = videoRangeType?.toLowerCase() ?? '';

      if (lRangeType.contains('dovi') || lRangeType.contains('dolby')) {
        return true;
      }
      if (lRange.contains('dovi') || lRange.contains('dolby')) return true;
      if (lCodec.contains('dvh') || lCodec.contains('dovi')) return true;

      if (videoRange != null || videoRangeType != null) return false;
    }
    if (source != null) return isDolbyVision(source);
    return false;
  }

  static bool _checkHdr(
    EmbyRawMediaSource? source,
    ProbeResult? probe,
    String? videoRange,
    String? videoRangeType,
  ) {
    if (probe != null) {
      final lRange = videoRange?.toLowerCase() ?? '';
      final lRangeType = videoRangeType?.toLowerCase() ?? '';
      final hasHdrSignal =
          lRange.contains('hdr') ||
          lRange.contains('dovi') ||
          lRangeType.contains('hdr') ||
          lRangeType.contains('dovi') ||
          lRangeType.contains('hlg');

      if (hasHdrSignal) return true;

      if (videoRange != null || videoRangeType != null) return false;
    }
    if (source != null) {
      if (isHdr(source)) return true;
      final video = findVideoStream(source);
      if (video != null) {
        final rangeType = (video.extra['VideoRangeType'] as String? ?? '')
            .toLowerCase();
        if (rangeType.contains('hlg')) return true;
      }
      return false;
    }
    return false;
  }

  static VideoRangeCategory _classifyHdr(
    String? videoRangeType,
    String? videoRange,
  ) {
    final lRangeType = videoRangeType?.toLowerCase() ?? '';
    if (lRangeType.contains('hlg')) return VideoRangeCategory.hlg;
    if (lRangeType.contains('hdr10')) return VideoRangeCategory.hdr10;
    if (lRangeType.contains('hdr')) return VideoRangeCategory.hdr10;

    final lRange = videoRange?.toLowerCase() ?? '';
    if (lRange.contains('hlg')) return VideoRangeCategory.hlg;
    if (lRange.contains('hdr')) return VideoRangeCategory.hdr10;

    return VideoRangeCategory.unknown;
  }
}
