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

import re
import hashlib
import time
from modules import kodi_utils, settings

# Les choix affichés sont liés au pays de certification configuré dans Métadonnées > Pays de certification.
# La valeur numérique sert seulement à comparer les classifications entre elles.
REGION_CHOICES = {
	'US': (
		{'key': 'G', 'label': 'G / TV-G', 'age': 0},
		{'key': 'PG', 'label': 'PG / TV-PG', 'age': 7},
		{'key': 'PG-13', 'label': 'PG-13 / TV-14', 'age': 14},
		{'key': 'R', 'label': 'R / TV-MA', 'age': 17},
		{'key': 'NC-17', 'label': 'NC-17', 'age': 18},
	),
	'CA': (
		{'key': 'G', 'label': 'G', 'age': 0},
		{'key': 'PG', 'label': 'PG', 'age': 8},
		{'key': '14A', 'label': '14A / 13+', 'age': 14},
		{'key': '18A', 'label': '18A / 16+', 'age': 18},
		{'key': 'R', 'label': 'R / A / 18+', 'age': 18},
	),
	'FR': (
		{'key': 'U', 'label': 'Tous publics', 'age': 0},
		{'key': '10', 'label': '10', 'age': 10},
		{'key': '12', 'label': '12', 'age': 12},
		{'key': '16', 'label': '16', 'age': 16},
		{'key': '18', 'label': '18', 'age': 18},
	),
	'GB': (
		{'key': 'U', 'label': 'U', 'age': 0},
		{'key': 'PG', 'label': 'PG', 'age': 8},
		{'key': '12', 'label': '12 / 12A', 'age': 12},
		{'key': '15', 'label': '15', 'age': 15},
		{'key': '18', 'label': '18 / R18', 'age': 18},
	),
	'DE': (
		{'key': '0', 'label': 'FSK 0', 'age': 0},
		{'key': '6', 'label': 'FSK 6', 'age': 6},
		{'key': '12', 'label': 'FSK 12', 'age': 12},
		{'key': '16', 'label': 'FSK 16', 'age': 16},
		{'key': '18', 'label': 'FSK 18', 'age': 18},
	),
	'ES': (
		{'key': 'APTA', 'label': 'APTA', 'age': 0},
		{'key': '7', 'label': '7', 'age': 7},
		{'key': '12', 'label': '12', 'age': 12},
		{'key': '16', 'label': '16', 'age': 16},
		{'key': '18', 'label': '18 / X', 'age': 18},
	),
	'IT': (
		{'key': 'T', 'label': 'T', 'age': 0},
		{'key': '6', 'label': 'VM6', 'age': 6},
		{'key': '14', 'label': 'VM14', 'age': 14},
		{'key': '18', 'label': 'VM18', 'age': 18},
	),
	'AU': (
		{'key': 'G', 'label': 'G', 'age': 0},
		{'key': 'PG', 'label': 'PG', 'age': 8},
		{'key': 'M', 'label': 'M', 'age': 15},
		{'key': 'MA15+', 'label': 'MA15+', 'age': 15},
		{'key': 'R18+', 'label': 'R18+ / X18+', 'age': 18},
	),
	'BR': (
		{'key': 'L', 'label': 'L', 'age': 0},
		{'key': '10', 'label': '10', 'age': 10},
		{'key': '12', 'label': '12', 'age': 12},
		{'key': '14', 'label': '14', 'age': 14},
		{'key': '16', 'label': '16', 'age': 16},
		{'key': '18', 'label': '18', 'age': 18},
	),
}

DEFAULT_BY_COUNTRY = {
	'US': 'PG-13', 'CA': '14A', 'FR': '12', 'GB': '12', 'DE': '12',
	'ES': '12', 'IT': '14', 'AU': 'M', 'BR': '12'
}

CERTIFICATION_AGE_MAP = {
	'US': {
		'G': 0, 'TV-Y': 0, 'TV-G': 0,
		'PG': 7, 'TV-Y7': 7, 'TV-Y7-FV': 7, 'TV-PG': 7,
		'PG-13': 13, 'TV-14': 14,
		'R': 17, 'TV-MA': 17,
		'NC-17': 18, 'X': 18
	},
	'CA': {'G': 0, 'PG': 8, '13+': 13, '14A': 14, '16+': 16, '18A': 18, 'R': 18, 'A': 18, '18+': 18},
	'FR': {'U': 0, 'TP': 0, 'TOUS PUBLICS': 0, '10': 10, '-10': 10, '12': 12, '-12': 12, '16': 16, '-16': 16, '18': 18, '-18': 18},
	'GB': {'U': 0, 'PG': 8, '12': 12, '12A': 12, '15': 15, '18': 18, 'R18': 18},
	'DE': {'0': 0, 'FSK0': 0, '6': 6, 'FSK6': 6, '12': 12, 'FSK12': 12, '16': 16, 'FSK16': 16, '18': 18, 'FSK18': 18},
	'ES': {'APTA': 0, 'TP': 0, '7': 7, '12': 12, '16': 16, '18': 18, 'X': 18},
	'IT': {'T': 0, 'VM6': 6, '6': 6, 'VM14': 14, '14': 14, 'VM18': 18, '18': 18},
	'AU': {'G': 0, 'PG': 8, 'M': 15, 'MA15+': 15, 'R18+': 18, 'X18+': 18},
	'BR': {'L': 0, 'AL': 0, '10': 10, '12': 12, '14': 14, '16': 16, '18': 18},
}

SCOPE_SETTING = {
	'movies': 'parental.apply_movies',
	'tvshows': 'parental.apply_tvshows',
	'family': 'parental.apply_family',
	'cartoons': 'parental.apply_cartoons',
	'lists': 'parental.apply_lists'
}

LIST_ACTIONS = {
	'tmdb_watchlist', 'tmdb_favorite', 'tmdb_recommendations',
	'trakt_collection', 'trakt_watchlist', 'trakt_favorites', 'trakt_collection_lists', 'trakt_droplist',
	'mdblist_collection', 'mdblist_watchlist', 'mdblist_favorites',
	'imdb_watchlist', 'imdb_user_list_contents',
	'in_progress_movies', 'in_progress_tvshows', 'trakt_in_progress_tvshows',
	'favourites_movies', 'favourites_movies_all', 'favourites_tvshows', 'favourites_tvshows_all', 'watched_movies', 'watched_tvshows'
}

LIST_ACTION_PREFIXES = ('mdblist_', 'imdb_')
CARTOON_ACTION_PREFIXES = ('tmdb_movies_family_animation_', 'tmdb_tv_family_animation_')
FAMILY_ACTION_PREFIXES = ('tmdb_movies_family_', 'tmdb_tv_family_')
ANIME_ACTION_PREFIXES = ('tmdb_moviesanime_', 'trakt_moviesanime_', 'tmdb_tvanime_', 'trakt_tvanime_')


def _setting_bool(setting_id, default='false'):
	return kodi_utils.get_setting(setting_id, default) == 'true'


PIN_HASH_SETTING = 'parental.pin_hash'
UNLOCKED_SETTING = 'parental.settings_unlocked'
PIN_SALT = 'alkoFlix.parental.pin.v1'


def normalize_pin(pin):
	pin = str(pin or '').strip()
	return pin if re.match(r'^\d{4}$', pin) else ''


def hash_pin(pin):
	pin = normalize_pin(pin)
	if not pin: return ''
	return hashlib.sha256(('%s:%s' % (PIN_SALT, pin)).encode('utf-8')).hexdigest()


def has_pin():
	return bool(kodi_utils.get_setting(PIN_HASH_SETTING, ''))


def verify_pin(pin):
	stored_hash = kodi_utils.get_setting(PIN_HASH_SETTING, '')
	return bool(stored_hash and hash_pin(pin) == stored_hash)


def set_pin(pin):
	pin_hash = hash_pin(pin)
	if not pin_hash: return False
	kodi_utils.set_setting(PIN_HASH_SETTING, pin_hash)
	return True


def settings_unlocked():
	return _setting_bool(UNLOCKED_SETTING, 'false')


def unlock_settings():
	# Déverrouillage temporaire : le service reverrouille dès que la fenêtre
	# des réglages d'extension est quittée.
	kodi_utils.set_setting(UNLOCKED_SETTING, 'true')
	try:
		kodi_utils.set_property('alkoflix_parental_settings_unlocked_at', str(int(time.time())))
		kodi_utils.clear_property('alkoflix_parental_settings_window_seen')
	except Exception:
		pass


def lock_settings():
	if _setting_bool(UNLOCKED_SETTING, 'false'): kodi_utils.set_setting(UNLOCKED_SETTING, 'false')
	try:
		kodi_utils.clear_property('alkoflix_parental_settings_unlocked_at')
		kodi_utils.clear_property('alkoflix_parental_settings_window_seen')
	except Exception:
		pass


def current_country():
	try: return settings.certification_country()
	except: return 'FR'


def choices_for_country(country=None):
	country = (country or current_country() or 'FR').upper()
	return list(REGION_CHOICES.get(country) or REGION_CHOICES['FR'])


def default_choice(country=None):
	country = (country or current_country() or 'FR').upper()
	default_key = DEFAULT_BY_COUNTRY.get(country, DEFAULT_BY_COUNTRY['FR'])
	for item in choices_for_country(country):
		if item['key'] == default_key: return item
	return choices_for_country(country)[0]


def selected_choice(country=None):
	country = (country or current_country() or 'FR').upper()
	selected_key = kodi_utils.get_setting('parental.rating', '')
	for item in choices_for_country(country):
		if item['key'] == selected_key: return item
	return default_choice(country)


def enabled():
	return _setting_bool('parental.enabled', 'false')


def action_scope(action='', media_type='movie'):
	action = str(action or '').lower()
	media_type = str(media_type or '').lower()
	if action.startswith(ANIME_ACTION_PREFIXES): return 'anime'
	if action.startswith(CARTOON_ACTION_PREFIXES): return 'cartoons'
	if action.startswith(FAMILY_ACTION_PREFIXES): return 'family'
	if action in LIST_ACTIONS or action.startswith(LIST_ACTION_PREFIXES): return 'lists'
	if media_type in ('tv', 'tvshow', 'series'): return 'tvshows'
	return 'movies'


def hide_anime_menu():
	# Les animés japonais sont volontairement traités à part :
	# les classifications sont trop incomplètes/variables pour un filtrage fiable par fiche.
	return enabled() and _setting_bool('parental.hide_anime_menu', 'false')


def applies_to_action(action='', media_type='movie'):
	if not enabled(): return False
	scope = action_scope(action, media_type)
	if scope == 'anime': return False
	if _setting_bool('parental.apply_all', 'true'): return True
	return _setting_bool(SCOPE_SETTING.get(scope, ''), 'true')


def _normalize(value):
	value = str(value or '').strip().upper()
	if not value: return ''
	value = value.replace('RATED ', '').replace('CLASSIFICATION ', '')
	value = value.replace('FSK ', 'FSK')
	value = re.sub(r'\s+', '', value)
	return value


def certification_age(certificate='', country=None):
	certificate = str(certificate or '').strip()
	if not certificate: return None
	country = (country or current_country() or 'FR').upper()
	age_map = CERTIFICATION_AGE_MAP.get(country, {})
	candidates = [certificate]
	for separator in ('/', ',', '|', ';'):
		if separator in certificate:
			candidates.extend([part.strip() for part in certificate.split(separator)])
	ages = []
	for candidate in candidates:
		normalized = _normalize(candidate)
		if not normalized or normalized in ('NR', 'N/A', 'NOTRATED', 'UNRATED'):
			continue
		if normalized in age_map:
			ages.append(age_map[normalized])
			continue
		# Plusieurs pays utilisent simplement le chiffre dans la certification (ex. 13+, FSK12, VM14).
		numeric = re.search(r'(\d{1,2})', normalized)
		if numeric:
			try: ages.append(int(numeric.group(1)))
			except: pass
		elif normalized in ('X', 'XXX'):
			ages.append(18)
	if not ages: return None
	return max(ages)


def rating_allowed(certificate='', action='', media_type='movie'):
	if not applies_to_action(action, media_type): return True
	country = current_country()
	age = certification_age(certificate, country)
	# Les fiches sans classification fiable sont contrôlées par une option dédiée.
	# Par défaut, elles restent autorisées afin d'éviter de vider des menus entiers après une mise à jour.
	if age is None: return _setting_bool('parental.allow_unrated', 'true')
	return age <= int(selected_choice(country).get('age', 99))


def meta_allowed(meta, action='', media_type='movie'):
	try: certificate = (meta or {}).get('mpaa') or (meta or {}).get('certification') or ''
	except: certificate = ''
	return rating_allowed(certificate, action, media_type)


def catalogue_item_allowed(item, catalogue_group='', media_type='movie'):
	# Les catalogues personnalisés ne sont pas filtrés par le contrôle parental.
	# Leurs métadonnées/certifications sont trop variables et peuvent vider des menus entiers.
	return True
