import '../../contracts/trakt/trakt_ids.dart';
import '../../contracts/trakt/trakt_scrobble_target.dart';


abstract final class TraktMediaMatcher {
  const TraktMediaMatcher._();


  static TraktScrobbleTarget? match({
    required String? itemType,
    required String itemName,
    required int? productionYear,
    required Map<String, String> providerIds,
    Map<String, String> seriesProviderIds = const {},
    String? seriesName,
    int? seriesProductionYear,
    int? parentIndexNumber,
    int? itemIndexNumber,
  }) {
    switch (itemType) {
      case 'Movie':
        return _matchMovie(itemName, productionYear, providerIds);
      case 'Episode':
        return _matchEpisode(
          ownIds: providerIds,
          seriesIds: seriesProviderIds,
          seriesName: seriesName,
          seriesYear: seriesProductionYear,
          season: parentIndexNumber,
          number: itemIndexNumber,
        );
      default:
        return null;
    }
  }

  static TraktScrobbleTarget? _matchMovie(
    String name,
    int? year,
    Map<String, String> providerIds,
  ) {
    final ids = _idsFrom(providerIds);
    final title = name.trim();
    if (!ids.hasReliableId && title.isEmpty) return null;
    return TraktScrobbleTarget.movie(title: title, year: year, ids: ids);
  }

  static TraktScrobbleTarget? _matchEpisode({
    required Map<String, String> ownIds,
    required Map<String, String> seriesIds,
    required String? seriesName,
    required int? seriesYear,
    required int? season,
    required int? number,
  }) {
    final episodeIds = _idsFrom(ownIds);
    final showIds = _idsFrom(seriesIds);
    final title = (seriesName ?? '').trim();

    if (episodeIds.hasReliableId) {
      return TraktScrobbleTarget.episode(
        showTitle: title,
        showYear: seriesYear,
        showIds: showIds,
        season: season,
        number: number,
        episodeIds: episodeIds,
      );
    }

    final hasShowIdentity = showIds.hasReliableId || title.isNotEmpty;
    if (hasShowIdentity && season != null && number != null) {
      return TraktScrobbleTarget.episode(
        showTitle: title,
        showYear: seriesYear,
        showIds: showIds,
        season: season,
        number: number,
        episodeIds: episodeIds,
      );
    }

    return null;
  }


  static TraktIds _idsFrom(Map<String, String> providerIds) {
    if (providerIds.isEmpty) return const TraktIds();
    final lower = <String, String>{};
    for (final entry in providerIds.entries) {
      final k = entry.key.trim().toLowerCase();
      final v = entry.value.trim();
      if (k.isNotEmpty && v.isNotEmpty) lower[k] = v;
    }
    return TraktIds(
      trakt: _parseInt(lower['trakt']),
      imdb: lower['imdb'],
      tmdb: _parseInt(lower['tmdb']),
      tvdb: _parseInt(lower['tvdb']),
      slug: lower['slug'],
    );
  }

  static int? _parseInt(String? raw) {
    if (raw == null || raw.isEmpty) return null;
    return int.tryParse(raw);
  }
}
