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

const _tag = 'MediaSourceMeta';

class MediaSourceMetadataResolver {
  MediaSourceMetadataResolver({required this._probeService});

  final MediaProbeService _probeService;

  Future<ProbeResult?> resolve({
    required EmbyRawMediaSource? source,
    required String streamUrl,
    EmbyRawItem? item,
    Duration timeout = const Duration(seconds: 5),
  }) async {
    if (source == null) {
      return _probeService.probe(streamUrl, timeout: timeout);
    }

    final sourceMetadata = _metadataFromSource(source);
    if (sourceMetadata != null) {
      AppLogger.debug(
        _tag,
        'source metadata hit sourceId=${source.Id ?? '<null>'} '
        'container=${source.Container}',
      );
      return sourceMetadata;
    }

    final itemMetadata = _metadataFromItem(item, source);
    if (itemMetadata != null) return itemMetadata;

    AppLogger.debug(
      _tag,
      'metadata empty for sourceId=${source.Id ?? '<null>'} '
      'container=${source.Container}, probing stream',
    );
    return _probeService.probe(streamUrl, timeout: timeout);
  }

  ProbeResult? _metadataFromItem(EmbyRawItem? item, EmbyRawMediaSource source) {
    final itemSources = _itemMediaSources(item);
    if (itemSources.isEmpty) return null;

    Map<String, dynamic>? matched;
    var matchMode = 'none';
    for (final candidate in itemSources) {
      if (candidate['Id'] == source.Id) {
        matched = candidate;
        matchMode = 'matchById';
        break;
      }
    }
    if (matched == null && itemSources.length == 1) {
      matched = itemSources.first;
      matchMode = 'singleSource';
    }
    if (matched == null) {
      AppLogger.warn(
        _tag,
        'no matching item MediaSource for sourceId=${source.Id ?? '<null>'}',
      );
      return null;
    }

    final fallbackSource = EmbyRawMediaSource.fromJson(matched);
    final metadata = _metadataFromSource(fallbackSource);
    if (metadata == null) {
      AppLogger.warn(
        _tag,
        'item.MediaSources matched but its video metadata is empty '
        '(sourceId=${source.Id ?? '<null>'}, $matchMode)',
      );
      return null;
    }

    AppLogger.debug(
      _tag,
      'backfilled metadata from item.MediaSources '
      'sourceId=${source.Id ?? '<null>'} ($matchMode)',
    );
    return metadata;
  }

  List<Map<String, dynamic>> _itemMediaSources(EmbyRawItem? item) {
    final raw = item?.extra['MediaSources'];
    if (raw is! List) return const <Map<String, dynamic>>[];

    final sources = <Map<String, dynamic>>[];
    for (final entry in raw) {
      if (entry is Map) {
        sources.add(Map<String, dynamic>.from(entry));
      }
    }
    return sources;
  }

  ProbeResult? _metadataFromSource(EmbyRawMediaSource source) {
    final video = findVideoStream(source);
    if (video == null) return null;

    return ProbeResult(
      videoCodec: video.Codec,
      videoRange: video.extra['VideoRange'] as String?,
      videoRangeType: video.extra['VideoRangeType'] as String?,
    );
  }
}
