# -*- coding: utf-8 -*-
# plugin.video.alkoflix
# resources/lib/modules/favourites_sync.py

from modules import kodi_utils, settings
from modules.utils import get_datetime
from caches.favourites_cache import favourites_cache, local_favourite_keys, MOVIE_FAVOURITE_TYPES, TV_FAVOURITE_TYPES

logger = kodi_utils.logger
get_setting, set_setting = kodi_utils.get_setting, kodi_utils.set_setting


def _fetch_meta(media_type, tmdb_id):
	try:
		from indexers.metadata import movie_meta, tvshow_meta
		user_info = settings.metadata_user_info()
		if media_type == 'movie': return movie_meta('tmdb_id', tmdb_id, user_info, get_datetime())
		if media_type == 'tvshow': return tvshow_meta('tmdb_id', tmdb_id, user_info, get_datetime())
	except Exception as e:
		logger('alkoFlix favourites initial sync meta failed', '%s | %s | %s' % (media_type, tmdb_id, e))
	return None


def _store(media_type, tmdb_id, title=''):
	if not tmdb_id or media_type not in ('movie', 'tvshow'): return False
	# Les imports depuis Trakt/TMDb n'ont aucun contexte de menu alkoFlix.
	# Ils doivent donc rester dans les paniers globaux movie/tvshow, sans
	# reclassement automatique par genres TMDb. Les catégories Famille, Animation,
	# Docus, Anime, etc. sont réservées aux ajouts faits depuis ces menus.
	if not title:
		meta = _fetch_meta(media_type, tmdb_id)
		if meta: title = meta.get('title') or meta.get('rootname') or ''
	success = False
	for key in local_favourite_keys(media_type, media_type):
		success = favourites_cache.add_to_favourites(key, tmdb_id, title or str(tmdb_id)) or success
	return success


def _import_trakt():
	if not get_setting('trakt_user', ''): return 0
	from indexers import trakt_api
	count = 0
	for media_type in ('movie', 'tvshow'):
		for item in trakt_api.trakt_fetch_favorites(media_type) or []:
			ids = item.get('media_ids') or {}
			if _store(media_type, ids.get('tmdb'), item.get('title')): count += 1
	return count


def _import_tmdb():
	if not get_setting('tmdb.token', ''): return 0
	from indexers import tmdb_api
	count = 0
	for media_type, tmdb_type in (('movie', 'movie'), ('tvshow', 'tv')):
		for item in tmdb_api.all_items(tmdb_api.favorite, tmdb_type) or []:
			if _store(media_type, item.get('id'), item.get('title') or item.get('name')): count += 1
	return count


def import_external_favourites(source=None, force=False):
	try: source = int(source if source is not None else settings.favourites_import_source())
	except: source = 0
	provider_names = {1: 'Trakt', 3: 'TMDb', 4: 'alkoPastes'}
	if source not in (1, 3, 4): return {'success': False, 'source': source, 'provider': '', 'count': 0, 'error': 'disabled'}
	if source == 4:
		try:
			from modules.alkopastes_backup import favourites_single_device_mode
			if favourites_single_device_mode():
				logger('alkoFlix favourites initial sync', 'Skipped | source=4 | multi_device_disabled')
				return {'success': False, 'source': source, 'provider': provider_names[source], 'count': 0, 'error': 'multi_device_disabled'}
		except Exception: pass
	setting_key = 'favourites.sync.initialized.source'
	if not force and get_setting(setting_key, '') == str(source):
		return {'success': True, 'source': source, 'provider': provider_names[source], 'count': 0, 'skipped': True}
	logger('alkoFlix favourites initial sync', 'Starting | source=%s' % source)
	try:
		if source == 1: count = _import_trakt()
		elif source == 3: count = _import_tmdb()
		else:
			from modules.alkopastes_backup import import_alkopastes_favourites
			result = import_alkopastes_favourites()
			if not result.get('success'):
				error = result.get('error') or 'alkoPastes import failed'
				if error == 'missing_backup':
					logger('alkoFlix favourites initial sync', 'Skipped | source=%s | no alkoPastes backup found' % source)
					return {'success': False, 'source': source, 'provider': provider_names[source], 'count': 0, 'error': 'missing_backup'}
				raise Exception(error)
			count = result.get('count', 0)
		set_setting(setting_key, str(source))
		logger('alkoFlix favourites initial sync', 'Finished | source=%s | imported=%s' % (source, count))
		return {'success': True, 'source': source, 'provider': provider_names[source], 'count': count}
	except Exception as e:
		logger('alkoFlix favourites initial sync', 'Failed | source=%s | %s: %s' % (source, type(e).__name__, e))
		return {'success': False, 'source': source, 'provider': provider_names.get(source, ''), 'count': 0, 'error': '%s: %s' % (type(e).__name__, e)}



def _backup_counts(result):
	counts = (result or {}).get('counts') or {}
	return {
		'movies': int(counts.get('movies') or 0),
		'shows': int(counts.get('tvshows') or 0),
		'seasons': int(counts.get('seasons') or 0),
		'episodes': int(counts.get('episodes') or 0),
		'people': int(counts.get('people') or 0),
		'collections': int(counts.get('collections') or 0)
	}

def sync_local_favourites_to_external(source=None):
	source = 4
	provider_name = 'alkoPastes'
	logger('alkoFlix favourites alkoPastes sync', 'Starting')
	try:
		from modules.alkopastes_backup import export_local_favourites_to_alkopastes, favourites_single_device_mode
		if favourites_single_device_mode():
			logger('alkoFlix favourites alkoPastes sync', 'Skipped | multi_device_disabled')
			return {'success': False, 'source': source, 'provider': provider_name, 'error': 'multi_device_disabled'}
		backup_result = export_local_favourites_to_alkopastes(force=True)
		counts = _backup_counts(backup_result)
		if not backup_result.get('success'):
			return {'success': False, 'source': source, 'provider': provider_name, 'error': backup_result.get('error') or 'alkoPastes export failed', **counts}
		logger('alkoFlix favourites alkoPastes sync', 'Finished | %s' % counts)
		return {'success': True, 'source': source, 'provider': provider_name, **counts}
	except Exception as e:
		logger('alkoFlix favourites alkoPastes sync', 'Failed | %s: %s' % (type(e).__name__, e))
		return {'success': False, 'source': source, 'provider': provider_name, 'error': '%s: %s' % (type(e).__name__, e), 'movies': 0, 'shows': 0, 'seasons': 0, 'episodes': 0, 'people': 0, 'collections': 0}


def _local_movie_tv_ids():
	movies, shows = set(), set()
	for fav_type in MOVIE_FAVOURITE_TYPES:
		for item in favourites_cache.get_favourites(fav_type) or []:
			try: media_id = int(item.get('tmdb_id'))
			except Exception: continue
			if media_id: movies.add(media_id)
	for fav_type in TV_FAVOURITE_TYPES:
		for item in favourites_cache.get_favourites(fav_type) or []:
			try: media_id = int(item.get('tmdb_id'))
			except Exception: continue
			if media_id: shows.add(media_id)
	return sorted(movies), sorted(shows)


def _local_movie_tv_payload():
	movies, shows = _local_movie_tv_ids()
	payload = {}
	if movies: payload['movies'] = [{'ids': {'tmdb': media_id}} for media_id in movies]
	if shows: payload['shows'] = [{'ids': {'tmdb': media_id}} for media_id in shows]
	return payload, len(movies), len(shows)


def export_local_favourites_to_trakt():
	provider_name = 'Trakt'
	if not get_setting('trakt_user', ''):
		return {'success': False, 'provider': provider_name, 'error': 'not_authorized', 'movies': 0, 'shows': 0}
	payload, movies_count, shows_count = _local_movie_tv_payload()
	if not payload:
		return {'success': False, 'provider': provider_name, 'error': 'empty', 'movies': 0, 'shows': 0}
	try:
		from indexers import trakt_api
		result = trakt_api.call_trakt('sync/favorites', data=payload)
		if isinstance(result, dict) and (result.get('account_limit') or result.get('rate_limited') or result.get('status') == 420):
			return {'success': False, 'provider': provider_name, 'error': 'account_limit', 'movies': movies_count, 'shows': shows_count}
		if not isinstance(result, dict):
			return {'success': False, 'provider': provider_name, 'error': 'invalid_response', 'movies': movies_count, 'shows': shows_count}
		added = result.get('added') or {}
		existing = result.get('existing') or {}
		added_total = int(added.get('movies') or 0) + int(added.get('shows') or 0)
		existing_total = int(existing.get('movies') or 0) + int(existing.get('shows') or 0)
		try:
			trakt_api._clear_trakt_favourites_account_limit()
			trakt_api.trakt_sync_activities()
		except Exception: pass
		logger('alkoFlix favourites export', 'Trakt | movies=%s | shows=%s | added=%s | existing=%s' % (movies_count, shows_count, added_total, existing_total))
		return {'success': True, 'provider': provider_name, 'movies': movies_count, 'shows': shows_count, 'added': added_total, 'existing': existing_total}
	except Exception as e:
		logger('alkoFlix favourites export failed', 'Trakt | %s: %s' % (type(e).__name__, e))
		return {'success': False, 'provider': provider_name, 'error': '%s: %s' % (type(e).__name__, e), 'movies': movies_count, 'shows': shows_count}


def export_local_favourites_to_tmdb():
	provider_name = 'TMDb'
	if not get_setting('tmdb.token', ''):
		return {'success': False, 'provider': provider_name, 'error': 'not_authorized', 'movies': 0, 'shows': 0}
	movies, shows = _local_movie_tv_ids()
	if not movies and not shows:
		return {'success': False, 'provider': provider_name, 'error': 'empty', 'movies': 0, 'shows': 0}
	added, failed = 0, 0
	try:
		from indexers import tmdb_api
		for media_id in movies:
			try:
				item = {'media_type': 'movie', 'media_id': media_id, 'favorite': True}
				if tmdb_api.add_to_watchlist_favorite(item, 'favorite').get('success'): added += 1
				else: failed += 1
			except Exception: failed += 1
		for media_id in shows:
			try:
				item = {'media_type': 'tv', 'media_id': media_id, 'favorite': True}
				if tmdb_api.add_to_watchlist_favorite(item, 'favorite').get('success'): added += 1
				else: failed += 1
			except Exception: failed += 1
		try: tmdb_api.clear_tmdbl_cache()
		except Exception: pass
		logger('alkoFlix favourites export', 'TMDb | movies=%s | shows=%s | added=%s | failed=%s' % (len(movies), len(shows), added, failed))
		return {'success': failed == 0 or added > 0, 'provider': provider_name, 'movies': len(movies), 'shows': len(shows), 'added': added, 'failed': failed}
	except Exception as e:
		logger('alkoFlix favourites export failed', 'TMDb | %s: %s' % (type(e).__name__, e))
		return {'success': False, 'provider': provider_name, 'error': '%s: %s' % (type(e).__name__, e), 'movies': len(movies), 'shows': len(shows)}


def _clear_trakt_favourites_cache(trakt_api):
	try: trakt_api.trakt_cache.clear_trakt_collection_watchlist_data('favorites', 'movie')
	except Exception: pass
	try: trakt_api.trakt_cache.clear_trakt_collection_watchlist_data('favorites', 'tvshow')
	except Exception: pass


def delete_trakt_favourites():
	provider_name = 'Trakt'
	if not get_setting('trakt_user', ''):
		return {'success': False, 'provider': provider_name, 'error': 'not_authorized', 'movies': 0, 'shows': 0, 'deleted': 0}
	try:
		from indexers import trakt_api
		_clear_trakt_favourites_cache(trakt_api)
		movies_payload, shows_payload = [], []
		for item in trakt_api.trakt_fetch_favorites('movie') or []:
			ids = item.get('media_ids') or {}
			if ids: movies_payload.append({'ids': ids})
		for item in trakt_api.trakt_fetch_favorites('tvshow') or []:
			ids = item.get('media_ids') or {}
			if ids: shows_payload.append({'ids': ids})
		payload = {}
		if movies_payload: payload['movies'] = movies_payload
		if shows_payload: payload['shows'] = shows_payload
		if not payload:
			return {'success': False, 'provider': provider_name, 'error': 'empty', 'movies': 0, 'shows': 0, 'deleted': 0}
		result = trakt_api.call_trakt('sync/favorites/remove', data=payload)
		if not isinstance(result, dict):
			return {'success': False, 'provider': provider_name, 'error': 'invalid_response', 'movies': len(movies_payload), 'shows': len(shows_payload), 'deleted': 0}
		deleted = result.get('deleted') or {}
		deleted_movies = int(deleted.get('movies') or 0)
		deleted_shows = int(deleted.get('shows') or 0)
		try:
			trakt_api._clear_trakt_favourites_account_limit()
			_clear_trakt_favourites_cache(trakt_api)
			trakt_api.trakt_sync_activities()
		except Exception: pass
		total = deleted_movies + deleted_shows
		logger('alkoFlix favourites delete', 'Trakt | movies=%s | shows=%s | deleted=%s' % (deleted_movies, deleted_shows, total))
		return {'success': True, 'provider': provider_name, 'movies': deleted_movies, 'shows': deleted_shows, 'deleted': total}
	except Exception as e:
		logger('alkoFlix favourites delete failed', 'Trakt | %s: %s' % (type(e).__name__, e))
		return {'success': False, 'provider': provider_name, 'error': '%s: %s' % (type(e).__name__, e), 'movies': 0, 'shows': 0, 'deleted': 0}


def delete_tmdb_favourites():
	provider_name = 'TMDb'
	if not get_setting('tmdb.token', ''):
		return {'success': False, 'provider': provider_name, 'error': 'not_authorized', 'movies': 0, 'shows': 0, 'deleted': 0}
	try:
		from indexers import tmdb_api
		try: tmdb_api.clear_tmdbl_cache()
		except Exception: pass
		movies = tmdb_api.all_items(tmdb_api.favorite, 'movie') or []
		shows = tmdb_api.all_items(tmdb_api.favorite, 'tv') or []
		if not movies and not shows:
			return {'success': False, 'provider': provider_name, 'error': 'empty', 'movies': 0, 'shows': 0, 'deleted': 0}
		deleted_movies, deleted_shows, failed = 0, 0, 0
		for item in movies:
			try:
				payload = {'media_type': 'movie', 'media_id': item.get('id'), 'favorite': False}
				if item.get('id') and tmdb_api.add_to_watchlist_favorite(payload, 'favorite').get('success'): deleted_movies += 1
				else: failed += 1
			except Exception: failed += 1
		for item in shows:
			try:
				payload = {'media_type': 'tv', 'media_id': item.get('id'), 'favorite': False}
				if item.get('id') and tmdb_api.add_to_watchlist_favorite(payload, 'favorite').get('success'): deleted_shows += 1
				else: failed += 1
			except Exception: failed += 1
		try: tmdb_api.clear_tmdbl_cache()
		except Exception: pass
		total = deleted_movies + deleted_shows
		logger('alkoFlix favourites delete', 'TMDb | movies=%s | shows=%s | failed=%s' % (deleted_movies, deleted_shows, failed))
		return {'success': failed == 0 or total > 0, 'provider': provider_name, 'movies': deleted_movies, 'shows': deleted_shows, 'deleted': total, 'failed': failed}
	except Exception as e:
		logger('alkoFlix favourites delete failed', 'TMDb | %s: %s' % (type(e).__name__, e))
		return {'success': False, 'provider': provider_name, 'error': '%s: %s' % (type(e).__name__, e), 'movies': 0, 'shows': 0, 'deleted': 0}


def delete_external_favourites_from_provider(source=None):
	try: source = int(source)
	except Exception: source = 0
	if source == 1: return delete_trakt_favourites()
	if source == 3: return delete_tmdb_favourites()
	return {'success': False, 'provider': '', 'error': 'disabled', 'movies': 0, 'shows': 0, 'deleted': 0}


def export_local_favourites_to_provider(source=None):
	try: source = int(source)
	except Exception: source = 0
	if source == 1: return export_local_favourites_to_trakt()
	if source == 3: return export_local_favourites_to_tmdb()
	return {'success': False, 'provider': '', 'error': 'disabled', 'movies': 0, 'shows': 0}
