
# -*- coding: utf-8 -*-
import time
import requests
import xbmc
import xbmcgui
from datetime import datetime

from resources.lib.trakt.trakt_service import (
    get_trakt_headers,
    ProgressCacheManager,
    TraktAPI
)
from resources.lib.utils.log_utils import get_logger

log = get_logger()

TRAKT_API_BASE = "https://api.trakt.tv"
TRAKT_API_HISTORY_URL = f"{TRAKT_API_BASE}/sync/history"


def _notify(title, message, icon=xbmcgui.NOTIFICATION_INFO, time_ms=3000):
    xbmcgui.Dialog().notification(title, message, icon, time_ms)


def _utc_now():
    return datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.000Z')


def _get_json(url, params=None, auth=False, timeout=12):
    headers = get_trakt_headers(for_post=False)
    if not auth and headers and 'Authorization' in headers:
        # odstraň Authorization pro public call
        headers = {k: v for k, v in headers.items() if k.lower() != 'authorization'}
    try:
        r = requests.get(url, params=params or {}, headers=headers, timeout=timeout)
        if r.status_code == 429:
            time.sleep(int(r.headers.get('Retry-After', '3')))
            r = requests.get(url, params=params or {}, headers=headers, timeout=timeout)
        r.raise_for_status()
        return r.json()
    except Exception as e:
        log.error(f"GET {url} failed: {e}")
        return None


def _resolve_show_id_or_slug_from_tmdb(tmdb_id):
    """Z TMDb ID najdi Trakt identifikátor (slug nebo trakt id)."""
    try:
        if not tmdb_id or int(tmdb_id) <= 0:
            return None
    except Exception:
        return None
    url = f"{TRAKT_API_BASE}/search/tmdb/{int(tmdb_id)}"
    data = _get_json(url, params={"type": "show"}, auth=False)
    if not data or not isinstance(data, list):
        return None
    for row in data:
        show = row.get('show') or row
        ids = show.get('ids') or {}
        slug = ids.get('slug')
        trakt_id = ids.get('trakt')
        return slug or (str(trakt_id) if trakt_id else None)
    return None


def _fetch_season_episodes_with_aired(show_id_or_slug, season_num):
    """Vrátí list epizod s trakt id + first_aired pro danou sezónu."""
    if not show_id_or_slug or season_num is None:
        return []
    url = f"{TRAKT_API_BASE}/shows/{show_id_or_slug}/seasons/{int(season_num)}/episodes"
    data = _get_json(url, params={"extended": "full"}, auth=False)
    episodes = []
    if isinstance(data, list):
        for ep in data:
            ids = ep.get('ids') or {}
            ep_trakt = ids.get('trakt')
            first_aired = ep.get('first_aired')
            if ep_trakt:
                episodes.append({"trakt": ep_trakt, "first_aired": first_aired})
    return episodes


def _fetch_all_episodes_with_aired(show_id_or_slug):
    """Pro celý seriál (všechny sezóny > 0) vrátí list epizod s trakt id + first_aired."""
    url = f"{TRAKT_API_BASE}/shows/{show_id_or_slug}/seasons"
    seasons = _get_json(url, params={"extended": "min"}, auth=False) or []
    season_numbers = [s.get('number') for s in seasons if isinstance(s.get('number'), int) and s.get('number') > 0]
    all_eps = []
    for sn in season_numbers:
        eps = _fetch_season_episodes_with_aired(show_id_or_slug, sn)
        all_eps.extend([dict(e, season=sn) for e in eps])
    return all_eps


def _post_history(payload, label):
    """Obecná POST /sync/history a uživatelská notifikace/ log."""
    try:
        headers = get_trakt_headers(for_post=True)
        if not headers:
            _notify("Trakt", "Trakt není autorizován.", xbmcgui.NOTIFICATION_ERROR)
            return
        log.info(f"POST {TRAKT_API_HISTORY_URL} body={str(payload)[:800]}")
        r = requests.post(TRAKT_API_HISTORY_URL, json=payload, headers=headers, timeout=15)
        log.info(f"HTTP {r.status_code} resp={r.text[:800]}")
        if r.status_code in (200, 201):
            _notify("Trakt", f"{label} označeno jako zhlédnuté!")
        elif r.status_code == 204:
            _notify("Trakt", f"{label}: žádná změna (už bylo zhlédnuto).")
        else:
            _notify("Trakt", f"Chyba {r.status_code}", xbmcgui.NOTIFICATION_ERROR)
    except Exception as e:
        log.error(f"Network error: {e}")
        _notify("Trakt", "Chyba při odeslání na Trakt.", xbmcgui.NOTIFICATION_ERROR)


# ====================================================================
# VEŘEJNÉ FUNKCE – po každé úspěšné akci okamžitě aktualizujeme cache
# ====================================================================

def mark_episode_watched(tmdb_id, season_num, episode_num, tvdb_id=None, watched_mode='now'):
    """Označí jednu epizodu jako zhlédnutou (volitelně datum vysílání)."""
    try:
        if not tmdb_id or int(tmdb_id) <= 0:
            log.error("Chybí platné TMDb ID!")
            _notify("Trakt", "Chybí platné TMDb ID.", xbmcgui.NOTIFICATION_ERROR)
            return
    except Exception:
        _notify("Trakt", "Chybí platné TMDb ID.", xbmcgui.NOTIFICATION_ERROR)
        return

    if (watched_mode or 'now').lower() == 'aired':
        show_ident = _resolve_show_id_or_slug_from_tmdb(tmdb_id)
        url = f"{TRAKT_API_BASE}/shows/{show_ident}/seasons/{int(season_num)}/episodes/{int(episode_num)}"
        data = _get_json(url, params={"extended": "full"}, auth=False)
        if isinstance(data, dict):
            ids = (data.get('ids') or {})
            ep_trakt = ids.get('trakt')
            wa = data.get('first_aired') or _utc_now()
            if ep_trakt:
                payload = {"episodes": [{"ids": {"trakt": int(ep_trakt)}, "watched_at": wa}]}
                _post_history(payload, f"S{int(season_num):02d}E{int(episode_num):02d} (datum vysílání)")
                _update_single_show_cache(tmdb_id)
                return
        log.warning("Aired fetch failed – fallback NOW")

    # klasický payload (teď)
    headers = get_trakt_headers(for_post=True)
    if not headers:
        _notify("Trakt", "Trakt není autorizován.", xbmcgui.NOTIFICATION_ERROR)
        return
    ids = {"tmdb": int(tmdb_id)}
    if tvdb_id and str(tvdb_id).isdigit():
        ids["tvdb"] = int(tvdb_id)
    payload = {
        "shows": [{
            "ids": ids,
            "seasons": [{
                "number": int(season_num),
                "episodes": [{"number": int(episode_num)}]
            }]
        }]
    }
    _post_history(payload, f"S{int(season_num):02d}E{int(episode_num):02d}")
    _update_single_show_cache(tmdb_id)


def mark_season_watched(tmdb_id, season_num, tvdb_id=None, watched_mode='now'):
    """Označí celou sezónu jako zhlédnutou (volitelně datum vysílání epizod)."""
    try:
        if not tmdb_id or int(tmdb_id) <= 0:
            _notify("Trakt", "Chybí TMDb ID seriálu.", xbmcgui.NOTIFICATION_ERROR)
            return
    except Exception:
        _notify("Trakt", "Chybí TMDb ID seriálu.", xbmcgui.NOTIFICATION_ERROR)
        return

    if (watched_mode or 'now').lower() == 'aired':
        show_ident = _resolve_show_id_or_slug_from_tmdb(tmdb_id)
        eps = _fetch_season_episodes_with_aired(show_ident, season_num) if show_ident else []
        items = []
        now_iso = _utc_now()
        for e in eps:
            eid = e.get('trakt')
            wa = e.get('first_aired') or now_iso
            if eid:
                items.append({"ids": {"trakt": int(eid)}, "watched_at": wa})
        if items:
            payload = {"episodes": items}
            _post_history(payload, f"Sezóna S{int(season_num):02d} (datum vysílání)")
            _update_single_show_cache(tmdb_id)
            return
        log.warning("No aired dates, fallback SEASON/NOW")

    # fallback: standardní payload pro sezónu teď
    headers = get_trakt_headers(for_post=True)
    if not headers:
        _notify("Trakt", "Trakt není autorizován.", xbmcgui.NOTIFICATION_ERROR)
        return
    ids = {"tmdb": int(tmdb_id)}
    if tvdb_id and str(tvdb_id).isdigit():
        ids["tvdb"] = int(tvdb_id)
    payload = {
        "shows": [{
            "ids": ids,
            "seasons": [{"number": int(season_num)}]
        }]
    }
    _post_history(payload, f"Sezóna S{int(season_num):02d}")
    _update_single_show_cache(tmdb_id)


def mark_show_watched(tmdb_id, tvdb_id=None, watched_mode='now'):
    """Označí celý seriál jako zhlédnutý (volitelně datum vysílání)."""
    try:
        if not tmdb_id or int(tmdb_id) <= 0:
            _notify("Trakt", "Chybí TMDb ID seriálu.", xbmcgui.NOTIFICATION_ERROR)
            return
    except Exception:
        _notify("Trakt", "Chybí TMDb ID seriálu.", xbmcgui.NOTIFICATION_ERROR)
        return

    if (watched_mode or 'now').lower() == 'aired':
        show_ident = _resolve_show_id_or_slug_from_tmdb(tmdb_id)
        eps = _fetch_all_episodes_with_aired(show_ident) if show_ident else []
        items = []
        now_iso = _utc_now()
        for e in eps:
            eid = e.get('trakt')
            wa = e.get('first_aired') or now_iso
            if eid:
                items.append({"ids": {"trakt": int(eid)}, "watched_at": wa})
        if items:
            payload = {"episodes": items}
            _post_history(payload, "Celý seriál (datum vysílání)")
            _update_single_show_cache(tmdb_id)
            return
        log.warning("No aired dates, fallback SHOW/NOW")

    payload = {"shows": [{"ids": {"tmdb": int(tmdb_id)}}]}
    _post_history(payload, "Celý seriál")
    _update_single_show_cache(tmdb_id)


def mark_movie_watched(tmdb_id: int) -> None:
    """Označí film jako zhlédnutý."""
    try:
        if not tmdb_id or int(tmdb_id) <= 0:
            log.error("Chybí platné TMDb ID (movie)!")
            _notify("Trakt", "Chybí platné TMDb ID.", xbmcgui.NOTIFICATION_ERROR)
            return
        headers = get_trakt_headers(for_post=True)
        if not headers:
            _notify("Trakt", "Trakt není autorizován.", xbmcgui.NOTIFICATION_ERROR)
            return
        payload = {"movies": [{"ids": {"tmdb": int(tmdb_id)}}]}
        r = requests.post(TRAKT_API_HISTORY_URL, json=payload, headers=headers, timeout=10)
        log.info(f"HTTP {r.status_code} Response: {r.text[:500]}")
        if r.status_code in (200, 201):
            _notify("Trakt", "Film označen jako zhlédnutý!")
        elif r.status_code == 204:
            _notify("Trakt", "Žádná změna (už bylo zhlédnuto).")
        else:
            _notify("Trakt", f"Chyba {r.status_code}", xbmcgui.NOTIFICATION_ERROR)
    except Exception as e:
        log.error(f"Síťová chyba: {e}")
        _notify("Trakt", "Chyba při odeslání na Trakt.", xbmcgui.NOTIFICATION_ERROR)


# ====================================================================
# Pomocná funkce — rychlý update jednoho seriálu v progress_cache.json
# ====================================================================

def _update_single_show_cache(tmdb_id):
    """
    Rychlá aktualizace jednoho seriálu v metadata.db (pouze Trakt data)
    Nahrazuje starý JSON cache – mnohem rychlejší a spolehlivější.
    """
    try:
        from resources.lib.trakt.trakt_service import TraktAPI
        from resources.lib.database.metadata_db import db

        api = TraktAPI()

        # 1. Zkusíme najít Trakt ID podle TMDb ID
        trakt_data = api.search_by_tmdb(tmdb_id)
        if not trakt_data:
            log.warning(f"_update_single_show_cache: nenalezen Trakt záznam pro TMDb {tmdb_id}")
            return

        show = trakt_data[0].get('show') or {}
        trakt_id = show.get('ids', {}).get('trakt')
        if not trakt_id:
            return

        # 2. Stáhneme aktuální progress (bez cache)
        fresh = api.shows_progress_watched(str(trakt_id), cache_ttl=0) or {}

        # 3. Uložíme vše do centrální DB
        db.update(tmdb_id, {
            'media_type': 'tv',
            'trakt_episodes_completed': fresh.get('completed', 0),
            'title_en': show.get('title'),
            'year': show.get('year')
        }, source='trakt_single_update')

        log.info(f"Cache aktualizována pro TMDb {tmdb_id} (Trakt {trakt_id})")

    except Exception as e:
        log.error(f"_update_single_show_cache selhalo pro TMDb {tmdb_id}: {e}")