from logging import getLogger
from typing import override

from langcodes import Language

from scanner.identifiers.anilist import anilist_enrich_ids
from scanner.models.metadataid import MetadataId
from scanner.utils import uniq_by

from ..models.movie import Movie, SearchMovie
from ..models.serie import SearchSerie, Serie
from .provider import Provider

logger = getLogger(__name__)


class CompositeProvider(Provider):
	def __init__(self, tvdb: Provider, themoviedb: Provider):
		self._tvdb = tvdb
		self._themoviedb = themoviedb

	@property
	@override
	def name(self):
		return "composite"

	@override
	async def search_movies(
		self, title: str, year: int | None, *, language: list[Language]
	) -> list[SearchMovie]:
		return await self._themoviedb.search_movies(title, year, language=language)

	@override
	async def get_movie(self, external_id: dict[str, str]) -> Movie | None:
		ret = await self._themoviedb.get_movie(external_id)
		if ret is None:
			return None
		# we only use tvdb for collections, since tmdb doesn't have them for series
		info = await self._tvdb.get_movie(MetadataId.map_dict(ret.external_id))
		if info is None:
			return ret
		ret.staff = info.staff
		if info.collection is not None:
			ret.collection = info.collection
		ret.external_id = MetadataId.merge(ret.external_id, info.external_id)
		return ret

	@override
	async def search_series(
		self, title: str, year: int | None, *, language: list[Language]
	) -> list[SearchSerie]:
		return await self._tvdb.search_series(title, year, language=language)

	@override
	async def get_serie(
		self, external_id: dict[str, str], *, skip_entries=False
	) -> Serie | None:
		ret = await self._tvdb.get_serie(external_id)
		if ret is None:
			return None

		# some series have duplicates special numbers/episode numbers, sensitize them
		ret.entries = uniq_by(
			ret.entries, lambda x: (x.season_number, x.episode_number, x.number, x.slug)
		)

		try:
			ret = await anilist_enrich_ids(ret)
		except Exception as e:
			logger.error("Could not enrich with anidb ids", exc_info=e)

		# themoviedb has better global info than tvdb but tvdb has better entries info
		info = await self._themoviedb.get_serie(
			MetadataId.map_dict(ret.external_id), skip_entries=True
		)
		if info is None:
			return ret
		info.staff = ret.staff
		info.seasons = ret.seasons
		info.entries = ret.entries
		info.extras = ret.extras
		if ret.collection is not None:
			info.collection = ret.collection
		info.external_id = MetadataId.merge(ret.external_id, info.external_id)
		return info
