# -*- coding: utf-8 -*-
import xbmc
import xbmcaddon
import xbmcgui
import sys
import os
import xbmcvfs
import urllib.parse
import time
import html
from datetime import datetime
from resources.lib.utils.log_utils import get_logger

log = get_logger()

try:
    from resources.lib.trakt.trakt_service import trakt_progress_cache_refresh_full_ui, get_last_sync_time, set_last_sync_time
except ImportError as e:
    log.error(f'TraktService import error: {e}')
    # Voláme sys.exit(1), protože bez Traktu je service k ničemu.
    # Nicméně pro Kodi environment to může být příliš agresivní, necháme log a service se pokusí běžet dál.
    pass
try:
    from resources.lib.utils.background_enrich import (
        background_enrich_omdb_ratings, get_last_omdb_enrich_time, set_last_omdb_enrich_time,
        background_enrich_tmdb_titles,
        start_tmdb_audit_thread, get_last_tmdb_audit_time, set_last_tmdb_audit_time
    )
except ImportError as e:
    log.error(f'OMDb Enrich import error: {e}')
    pass

ADDON_ID = 'plugin.video.mmirousek_v3'

# Guard proti více instancí
try:
    win = xbmcgui.Window(10000)
    if win.getProperty('mm_scrobble_service_running') == '1':
        log.info('Už běží – ukončuji druhý start')
        sys.exit(0)
    win.setProperty('mm_scrobble_service_running', '1')
    log.info('Guard OK')
except Exception as e:
    log.warning(f'Guard property error: {e}')

try:
    __addon__ = xbmcaddon.Addon(ADDON_ID)
    __addon_path__ = xbmcvfs.translatePath(__addon__.getAddonInfo('path'))
    sys.path.append(os.path.join(__addon_path__, 'resources', 'lib'))
    from resources.lib.utils.cloud_sync import CloudSync
    from resources.lib.utils import telemetry
    from resources.lib.down.download_queue import load_queue, start_all, stop_all_downloads
    log.info('##### SERVICE.PY BĚŽÍ #####')

except Exception as e:
    log.error(f'FATÁLNÍ CHYBA při importu: {e}')
    sys.exit(1)


# Původní CloudSync start up tu byl odstraněn. V budoucnu se spouští při in_plugin_now.

# --- Pomocné funkce ---
PLUGIN_ID = 'plugin.video.mmirousek_v3'

def _is_in_our_plugin_ui() -> bool:
    """
    Vrátí True, pokud je aktuálně otevřený adresář v našem doplňku,
    tj. Container.FolderPath začíná na plugin://plugin.video.mmirousek_v3
    """
    try:
        path = xbmc.getInfoLabel('Container.FolderPath') or ''
        return path.startswith(f'plugin://{PLUGIN_ID}')
    except Exception:
        return False

def in_time_window(start_str, end_str):
    try:
        now = datetime.now().time()
        sh, sm = map(int, start_str.split(':'))
        eh, em = map(int, end_str.split(':'))
        start_t = datetime.now().replace(hour=sh, minute=sm, second=0).time()
        end_t = datetime.now().replace(hour=eh, minute=em, second=0).time()
        return (start_t <= now <= end_t) if start_t <= end_t else (now >= start_t or now <= end_t)
    except Exception:
        return False

def _set_auto_session(active: bool):
    try:
        xbmcgui.Window(10000).setProperty('mm_auto_dl_session', '1' if active else '')
        log.debug(f"AutoDownload session={'ON' if active else 'OFF'}")
    except Exception:
        pass

def _is_auto_session() -> bool:
    try:
        return xbmcgui.Window(10000).getProperty('mm_auto_dl_session') == '1'
    except Exception:
        return False

def _any_downloading() -> bool:
    try:
        q = load_queue() or []
        return any((i or {}).get('status') == 'downloading' for i in q)
    except Exception:
        return False

def _any_pending() -> bool:
    try:
        q = load_queue() or []
        return any((i or {}).get('status') == 'pending' for i in q)
    except Exception:
        return False


def _normalize_path(path: str) -> str:
    try:
        norm = (path or '').strip().replace('\\', '/').lower()
        return norm.rstrip('/')
    except Exception:
        return ''


def _get_download_roots():
    roots = []
    try:
        addon = xbmcaddon.Addon(ADDON_ID)
        keys = ('dfolder', 'dfolder_1', 'dfolder_2', 'dfolder_3')
        for key in keys:
            raw = addon.getSetting(key) or ''
            if not raw:
                continue
            try:
                translated = xbmcvfs.translatePath(raw) or raw
            except Exception:
                translated = raw
            norm = _normalize_path(translated)
            if norm and norm not in roots:
                roots.append(norm)
    except Exception:
        pass
    return roots


def _is_under_download_root(path: str) -> bool:
    norm_path = _normalize_path(path)
    if not norm_path:
        return False
    for root in _get_download_roots():
        if norm_path == root or norm_path.startswith(root + '/'):
            return True
    return False


def _consume_post_play_return_url():
    """
    Jednorázově obnoví listview URL uloženou při spuštění vyhledávání přes
    show_search_dialog (movie flow).
    """
    try:
        prop_key = 'sm3_post_play_return_url'

        def _normalize_plugin_return_url(url: str) -> str:
            raw = str(url or '').strip().strip('"')
            if not raw or raw.lower() == 'none':
                return ''
            raw = html.unescape(raw).replace('&amp;', '&')
            if not raw.startswith('plugin://plugin.video.mmirousek_v3'):
                return ''
            return raw

        def _extract_action(url: str) -> str:
            try:
                parsed = urllib.parse.urlparse(url)
                q = urllib.parse.parse_qs(parsed.query)
                return (q.get('action') or [''])[0]
            except Exception:
                return ''

        def _current_container_action() -> str:
            try:
                current = xbmc.getInfoLabel('Container.FolderPath') or ''
                parsed = urllib.parse.urlparse(current)
                q = urllib.parse.parse_qs(parsed.query)
                return (q.get('action') or [''])[0]
            except Exception:
                return ''

        def _alarmclock_safe_url(url: str) -> str:
            return str(url or '').replace(',', '%2C').replace('"', '%22').replace('|', '%7C')

        addon = xbmcaddon.Addon(ADDON_ID)
        win = xbmcgui.Window(10000)

        raw_prop = win.getProperty(prop_key) or ''
        raw_legacy = addon.getSetting('post_play_return_url') or ''

        # Jednorázová spotřeba: vždy vyčistit obě uložiště.
        win.clearProperty(prop_key)
        addon.setSetting('post_play_return_url', '')

        source = 'window_property' if str(raw_prop).strip() else 'legacy_setting'
        raw = raw_prop or raw_legacy
        url = _normalize_plugin_return_url(raw)

        if not url:
            if raw:
                log.warning(
                    f"Restore-after-play: neplatna return URL ze zdroje {source}: {raw}"
                )
            return

        action = _extract_action(url)
        if not action:
            safe_window_url = str(url).replace('"', '%22')
            xbmc.executebuiltin(f'ActivateWindow(Videos,"{safe_window_url}",return)')
            log.warning('Restore-after-play: chybi action, fallback na ActivateWindow')
            return

        current_action = _current_container_action()
        if current_action == 'search':
            log.info(
                f"Restore-after-play: skip forced return ({source}) action={action}; current action=search"
            )
            return

        safe_url = _alarmclock_safe_url(url)
        replace_cmd = f'Container.Update({safe_url},replace)'
        restore_delay = '00:00:05'

        # Jediný bezpečný návrat přes replace (bez vícenásobných navigačních závodů).
        # Drobné zpoždění nechá doběhnout interní návrat Kodi po ukončení přehrávání.
        try:
            xbmc.executebuiltin('CancelAlarm(sm3_search_jump,silent)')
            xbmc.executebuiltin('CancelAlarm(sm3_restore_after_play_late,silent)')
            xbmc.executebuiltin('CancelAlarm(sm3_restore_after_play_replace,silent)')
            xbmc.executebuiltin('CancelAlarm(sm3_restore_after_play,silent)')
        except Exception:
            pass
        xbmc.executebuiltin(
            f'AlarmClock(sm3_restore_after_play,{replace_cmd},{restore_delay},silent)'
        )
        log.info(
            f"Restore-after-play: scheduled single replace return ({source}) action={action} delay={restore_delay}"
        )
    except Exception as e:
        try:
            if 'url' in locals() and url:
                safe_url = _alarmclock_safe_url(url)
                cmd = f'Container.Update({safe_url},replace)'
                xbmc.executebuiltin(
                    f'AlarmClock(sm3_restore_after_play,{cmd},00:00:01,silent)'
                )
                log.warning(f'Restore-after-play failed, fallback AlarmClock/Container.Update: {e}')
                return
        except Exception:
            pass
        log.warning(f'Restore-after-play failed: {e}')


# --- Player monitor: reaguje jen na přehrávání z našeho doplňku ---
_last_playback_stop_time = 0.0
_last_playback_start_time = 0.0

class PlayerMonitor(xbmc.Player):
    def __init__(self):
        super().__init__()
        log.info('##### PlayerMonitor Inicializován #####')

    def _is_ours(self) -> bool:
        """
        Vrátí True, pokud aktuální přehrávání pochází z našeho doplňku.
        Kritéria (primární):
          - ListItem.Property('tmdb_id') je neprázdné
          - ListItem.Property('mediatype') ∈ {'movie','episode','tvshow'}
        Fallback (sekundární, pro jistotu):
          - getPlayingFile() obsahuje 'plugin.video.mmirousek_v3' nebo 'webshare.cz'
          - lokální soubor je pod download složkou addonu a má metadata epizody/filmu
        """
        try:
            tmdb_id = xbmc.getInfoLabel('ListItem.Property(tmdb_id)') or ''
            mediatype = (xbmc.getInfoLabel('ListItem.Property(mediatype)') or '').lower()
            if tmdb_id and mediatype in ('movie', 'episode', 'tvshow'):
                return True
            # fallback přes cestu souboru (např. pipe headers u Webshare)
            try:
                path = self.getPlayingFile() or ''
            except Exception:
                path = xbmc.getInfoLabel('Player.FilenameAndPath') or ''
            if 'plugin.video.mmirousek_v3' in path or 'webshare.cz' in path:
                return True

            # robust fallback pro offline lokální soubory bez tmdb_id property
            if _is_under_download_root(path):
                dbtype = (
                    xbmc.getInfoLabel('ListItem.DBTYPE')
                    or xbmc.getInfoLabel('VideoPlayer.DBTYPE')
                    or ''
                ).lower()
                if dbtype in ('movie', 'episode', 'tvshow'):
                    return True

                tvshowtitle = (
                    xbmc.getInfoLabel('VideoPlayer.TVShowTitle')
                    or xbmc.getInfoLabel('ListItem.TVShowTitle')
                    or ''
                )
                season = xbmc.getInfoLabel('VideoPlayer.Season') or ''
                episode = xbmc.getInfoLabel('VideoPlayer.Episode') or ''
                if tvshowtitle and season.isdigit() and episode.isdigit():
                    return True

                log.debug(f"_is_ours fallback: path je v download root, ale metadata nestačí ({path})")
        except Exception:
            pass
        return False

    def onPlayBackStarted(self):
        global _last_playback_start_time
        _last_playback_start_time = time.time()
        is_ours = self._is_ours()

        if not is_ours:
            log.info('onPlayBackStarted: ignored (not our plugin)')
        else:
            log.info('onPlayBackStarted – spouštím scrobble_delay.py')
            try:
                # __addon_path__ je inicializováno výše v service.py (viz tvůj kód)
                script_path = os.path.join(__addon_path__, 'scrobble_delay.py')
                encoded_path = urllib.parse.quote_plus(__addon_path__)
                xbmc.executebuiltin(f'RunScript("{script_path}",1,"{encoded_path}")')
            except Exception as e:
                log.error(f'onPlayBackStarted error: {e}')

        # Titulky auto: nezávisle na _is_ours() — po startu přehrávání často nejsou
        # ListItem.Property(tmdb_id) ani 'webshare.cz' v URL, ale mm_titulky_job
        # z PlayHandler je platný jen krátce (viz titulky_job_ts).
        try:
            from resources.lib.integrations.titulky_integration import (
                maybe_schedule_auto_titulky_from_player,
            )

            maybe_schedule_auto_titulky_from_player()
        except Exception as e:
            log.error(f'titulky auto schedule failed: {e}', exc_info=True)


    def onPlayBackStopped(self):
        """
        STOP: primárně rozhodujeme podle locku (trakt_payload_locked), protože
        po skončení přehrávání Kodi často ListItem.Property(...) už nevrátí.
        Pokud lock není aktivní, jako fallback použijeme původní _is_ours().
        """
        try:
            ADDON = xbmcaddon.Addon('plugin.video.mmirousek_v3')
            lock_active = (ADDON.getSetting('trakt_payload_locked') == 'true')
        except Exception:
            lock_active = False

        if lock_active:
            log.info('onPlayBackStopped: lock_active -> volám scrobble_stop()')
        else:
            if not self._is_ours():
                log.debug('onPlayBackStopped: ignored (not our plugin, no lock)')
                return

        log.info('onPlayBackStopped – scrobble_stop')
        try:
            global _last_playback_stop_time
            _last_playback_stop_time = time.time()
            from resources.lib.history.scrobble import scrobble_stop
            scrobble_stop()
            _consume_post_play_return_url()
        except Exception as e:
            log.error(f'onPlayBackStopped error: {e}')



    def onPlayBackPaused(self):
        """
        PAUSE: stejná strategie jako u STOP — lock má prioritu.
        Pokud není lock aktivní, ověříme ještě _is_ours() a případně přeskočíme.
        """
        try:
            ADDON = xbmcaddon.Addon('plugin.video.mmirousek_v3')
            lock_active = (ADDON.getSetting('trakt_payload_locked') == 'true')
        except Exception:
            lock_active = False

        if lock_active:
            log.debug('onPlayBackPaused: lock_active -> volám scrobble_pause()')
        else:
            if not self._is_ours():
                log.debug('onPlayBackPaused: ignored (not our plugin, no lock)')
                return

        try:
            from resources.lib.history.scrobble import scrobble_pause
            scrobble_pause()
        except Exception as e:
            log.error(f'onPlayBackPaused error: {e}')


    def onPlayBackEnded(self):
        """
        Video doběhlo přirozeně do konce → scrobble_stop() jako při ručním stopu.
        Bez tohoto callbacku Trakt nedostane /stop při přirozeném konci filmu/epizody.
        """
        try:
            ADDON = xbmcaddon.Addon('plugin.video.mmirousek_v3')
            lock_active = (ADDON.getSetting('trakt_payload_locked') == 'true')
        except Exception:
            lock_active = False

        if lock_active:
            log.info('onPlayBackEnded: lock_active -> volám scrobble_stop()')
        else:
            if not self._is_ours():
                log.debug('onPlayBackEnded: ignored (not our plugin, no lock)')
                return

        log.info('onPlayBackEnded – scrobble_stop')
        try:
            global _last_playback_stop_time
            _last_playback_stop_time = time.time()
            from resources.lib.history.scrobble import scrobble_stop
            scrobble_stop()
            _consume_post_play_return_url()
        except Exception as e:
            log.error(f'onPlayBackEnded error: {e}')


    def onPlayBackError(self):
        """
        Chyba přehrávání (síť, dekodér) → cleanup lock aby se nerozbil budoucí scrobble.
        """
        log.warning('onPlayBackError – čistím scrobble lock')
        try:
            global _last_playback_stop_time
            _last_playback_stop_time = time.time()
            from resources.lib.history.scrobble import _clean_settings
            _clean_settings()
        except Exception as e:
            log.error(f'onPlayBackError cleanup error: {e}')


# --- Settings Monitor for dfolder slots ---
class SettingsMonitor(xbmc.Monitor):
    def __init__(self, addon):
        super().__init__()
        self.addon = addon
        # První synchronizace při startu
        self.sync_dfolder()

    def onSettingsChanged(self):
        # Malá pauza, aby Kodi stihlo zapsat settings na disk/do paměti před čtením
        xbmc.sleep(500)
        self.sync_dfolder()

    def sync_dfolder(self):
        """
        Synchronizuje hodnotu aktivního slotu do hlavní proměnné 'dfolder'.
        Díky tomu zbytek kódu nemusíme měnit.
        """
        try:
            # Vždy čerstvá instance pro jistotu (dlouhoběžící služba vs settings cache)
            _t_addon = xbmcaddon.Addon('plugin.video.mmirousek_v3')
            raw_slot = _t_addon.getSetting('dfolder_slot') or '0'
            
            slot_idx = 0
            if raw_slot == 'Složka 1': slot_idx = 0
            elif raw_slot == 'Složka 2': slot_idx = 1
            elif raw_slot == 'Složka 3': slot_idx = 2
            else:
                try:
                    slot_idx = int(raw_slot)
                except ValueError:
                    slot_idx = 0
            
            slot_key = f'dfolder_{slot_idx + 1}'
            slot_path = _t_addon.getSetting(slot_key) or ''
            current_dfolder = _t_addon.getSetting('dfolder') or ''

            log.debug(f"sync_dfolder check: raw='{raw_slot}' slot={slot_idx+1} path='{slot_path}' current='{current_dfolder}'")

            if slot_path != current_dfolder:
                log.info(f"Syncing dfolder TO: slot={slot_idx+1} path='{slot_path}'")
                _t_addon.setSetting('dfolder', slot_path)
        except Exception as e:
            log.error(f"Settings sync error: {e}")


# --- Hlavní smyčka ---
if __name__ == '__main__':
    # ── STARTUP TELEMETRIE (MVP: pouze event "start") ──────────────────────
    try:
        telemetry.log_start_event(__addon__)
        telemetry.maybe_upload(__addon__)
    except Exception as e:
        log.debug(f'[Telemetry] startup skipped: {e}')

    # ── STARTUP CLOUD SYNC ─────────────────────────────────────────────────
    # Musí proběhnout PŘED spuštěním enrich vláken, aby se na novém zařízení
    # nejprve naplnila DB z cloudu a enrich pak nenačítal zbytečně z API.
    try:
        cs_startup = CloudSync(__addon__)
        if cs_startup.enabled and cs_startup.sync_on_start:
            log.info('[CloudSync] Startup sync PŘED enrichem → sync_all()')
            cs_startup.sync_all()
        else:
            log.info('[CloudSync] Startup sync přeskočen (disabled nebo sync_on_start=off)')
    except Exception as e:
        log.error(f'[CloudSync] Startup sync chyba: {e}')
    # ── KONEC STARTUP CLOUD SYNC ───────────────────────────────────────────


    try:
        # Kontrola, zda existuje Trakt modul a funkce
        if 'trakt_progress_cache_refresh_full_ui' in locals() or 'trakt_progress_cache_refresh_full_ui' in globals():
            
            # 1. Načtení nastavení (používáme existující __addon__ objekt)
            enabled = __addon__.getSettingBool('trakt_auto_sync_enabled')
            interval_hours = float(__addon__.getSetting('trakt_auto_sync_interval_h') or '24.0')
            INTERVAL_SECONDS = interval_hours * 3600
            
            log.info(f'Trakt auto-sync povolen: {enabled}, interval: {interval_hours}h ({INTERVAL_SECONDS}s)')

            if enabled:
                last_sync_ts = get_last_sync_time()
                current_ts = time.time()
                
                # 2. Kontrola, zda uplynul interval
                if current_ts - last_sync_ts > INTERVAL_SECONDS:
                    log.info('Spouštím full synchronizaci: Uplynul interval.')
                    
                    # --- VOLÁNÍ SYNCHRONIZACE ---
                    trakt_progress_cache_refresh_full_ui()
                    
                    # 3. Uložení nového času po dokončení
                    set_last_sync_time()
                    
                else:
                    time_remaining_h = (INTERVAL_SECONDS - (current_ts - last_sync_ts)) / 3600
                    log.info(f'Synchronizace přeskočena: Interval ({time_remaining_h:.2f} h) ještě neuplynul.')
            
        else:
            log.warning('TraktService moduly nejsou k dispozici, sync přeskočena.')


    except Exception as e:
        log.error(f'Chyba při spouštění jednorázové sync: {e}')

    try:
        if 'background_enrich_omdb_ratings' in locals() or 'background_enrich_omdb_ratings' in globals():
            
            # 1. Načtení nastavení
            enabled = __addon__.getSettingBool('omdb_enrich_enabled')
            interval_hours = float(__addon__.getSetting('omdb_enrich_interval_h') or '24.0')
            INTERVAL_SECONDS = interval_hours * 3600
            
            log.info(f'OMDB Enrich auto-enrich povolen: {enabled}, interval: {interval_hours}h ({INTERVAL_SECONDS}s)')

            if enabled:
                last_sync_ts = get_last_omdb_enrich_time()
                current_ts = time.time()

                # 2. Kontrola, zda uplynul interval
                if current_ts - last_sync_ts > INTERVAL_SECONDS:
                    log.info('Spouštím doplňování dat OMDb+TMDb titulů: Uplynul interval.')

                    # --- VOLÁNÍ JAKO DAEMON VLÁKNO (neblokuje start service.py) ---
                    def _run_omdb_enrich():
                        try:
                            background_enrich_tmdb_titles()
                            background_enrich_omdb_ratings()
                        except Exception as _e:
                            log.error(f'OMDb/TMDb enrich vlákno chyba: {_e}')

                    import threading as _threading
                    _t = _threading.Thread(target=_run_omdb_enrich, daemon=True, name='OmdbEnrichThread')
                    _t.start()
                    log.info('OMDb/TMDb enrich vlákno spuštěno.')

                    # Timestamp uložíme hned po startu (stejná logika jako TMDb Audit)
                    set_last_omdb_enrich_time()

                else:
                    time_remaining_h = (INTERVAL_SECONDS - (current_ts - last_sync_ts)) / 3600
                    log.info(f'Doplňování přeskočeno: Interval ({time_remaining_h:.2f} h) ještě neuplynul.')
            
        else:
            log.warning('Moduly pro OMDb doplňování nejsou k dispozici, přeskočeno.')


    except Exception as e:
        log.error(f'Chyba při spouštění OMDb enrich: {e}')

    # --- TMDb Audit Scanner (independenté vlákno, interval 1 h) ---
    try:
        if 'start_tmdb_audit_thread' in locals() or 'start_tmdb_audit_thread' in globals():
            enabled = __addon__.getSettingBool('tmdb_audit_auto_enabled')
            interval_hours = float(__addon__.getSetting('tmdb_audit_interval_h') or '1.0')
            INTERVAL_SECONDS = interval_hours * 3600

            log.info(f'TMDb audit auto: povolen={enabled}, interval={interval_hours}h ({INTERVAL_SECONDS}s)')

            if enabled:
                last_ts = get_last_tmdb_audit_time()
                current_ts = time.time()

                if current_ts - last_ts > INTERVAL_SECONDS:
                    log.info('Spouštím TMDb audit (vlákno): Uplynul interval.')
                    start_tmdb_audit_thread()   # daemon=True, nezdrzuje service
                    set_last_tmdb_audit_time()  # uložíš hned po start – několik sekund nevadí
                else:
                    remaining = (INTERVAL_SECONDS - (current_ts - last_ts)) / 3600
                    log.info(f'TMDb audit přeskočen: zbývá {remaining:.2f} h')
        else:
            log.warning('Modul TMDb audit není k dispozici, přeskočeno.')

    except Exception as e:
        log.error(f'Chyba při spouštění TMDb audit scheduleru: {e}')

# --- Konec jednorázové logiky ---

    # Trakt OAuth: kontrola expirace při startu služby (nezávisle na routeru / mm_trakt_auto_refresh_done)
    try:
        from resources.lib.trakt.trakt_module import refresh_trakt_token_by_expiry

        log.info('Trakt: kontrola expirace tokenu při startu služby')
        refresh_trakt_token_by_expiry(threshold_hours=12, notify_on_success=True)
    except Exception as e:
        log.warning(f'Trakt start refresh check: {e}')

    player_monitor = PlayerMonitor()
    monitor = SettingsMonitor(__addon__)
    last_auto_check = 0
    _trakt_expiry_check_interval_s = 6 * 3600  # každých 6 h – dlouhé relace Kodi
    last_trakt_expiry_check = time.time()
    in_plugin_prev = _is_in_our_plugin_ui()
    _startup_sync_done = cs_startup.enabled and cs_startup.sync_on_start  # přeskočí první on_start v loopu pokud startup sync proběhl
    log.info('Hlavní smyčka start')


    try:
        while not monitor.abortRequested():
            try:
                # --- SCROBBLE UPDATE ---
                from resources.lib.history.scrobble import progress_scrobble
                progress_scrobble()

                # --- Trakt token: periodická kontrola expirace (dlouhý běh Kodi bez restartu) ---
                _now_loop = time.time()
                if _now_loop - last_trakt_expiry_check >= _trakt_expiry_check_interval_s:
                    last_trakt_expiry_check = _now_loop
                    try:
                        from resources.lib.trakt.trakt_module import refresh_trakt_token_by_expiry

                        refresh_trakt_token_by_expiry(threshold_hours=12, notify_on_success=False)
                    except Exception as e:
                        log.warning(f'Trakt periodic refresh check: {e}')

                # --- DETEKCE OPUŠTĚNÍ UI DOPLŇKU ---
                in_plugin_now = _is_in_our_plugin_ui()

                # Guard proti falešnému "opuštění" během teardown přehrávání:
                # pokud je aktivní scrobble lock, považujeme to stále za interní playback.
                try:
                    lock_active_now = (__addon__.getSetting('trakt_payload_locked') == 'true')
                except Exception:
                    lock_active_now = False
                
                # Pokud hraje zrovna z našeho doplňku, považujeme za to, že jsme pořád V doplňku (protože kodi schová Container)
                is_playing_ours = False
                if xbmc.Player().isPlaying():
                    is_playing_ours = player_monitor._is_ours()
                
                if is_playing_ours or lock_active_now:
                    in_plugin_now = True

                # Uživatel právě VSTOUPIL do UI doplňku
                if not in_plugin_prev and in_plugin_now:
                    try:
                        from resources.lib.utils.cloud_sync import CloudSync
                        fresh_addon = xbmcaddon.Addon('plugin.video.mmirousek_v3')
                        cs_enter = CloudSync(fresh_addon)
                    # --- NOVÁ ČÁST: Zobrazení novinek po aktualizaci ---
                        try:
                            from resources.lib.utils.background_enrich import check_and_show_news
                            log.info("Zjišťuji, zda nedošlo k aktualizaci (zobrazení novinek)")
                            check_and_show_news()
                        except Exception as e:
                            log.error(f"ERROR in check_and_show_news: {e}")
                        # ---------------------------------------------------

                        # Ochranná lhůta po přehrávání (10s), aby se vyhnulo falešnému syncu po stopnutí videa
                        playback_cooldown = (time.time() - _last_playback_stop_time) < 10
                        if playback_cooldown:
                            log.info(f"Auto-sync při VSTUPU ignorován (lhůta po přehrávání: {time.time() - _last_playback_stop_time:.1f}s)")
                        elif _startup_sync_done:
                            # Startup sync již proběhl při startu service → první vstup přeskočíme
                            log.info("Auto-sync při VSTUPU přeskočen (startup sync již proběhl)")
                            _startup_sync_done = False  # další vstupy už syncovat normálně
                        elif cs_enter.enabled and cs_enter.sync_on_start:
                            log.info("Auto-sync při VSTUPU do doplňku → sync_all()")
                            cs_enter.sync_all()
                        else:
                            log.info("Auto-sync při vstupu do doplňku přeskočen (disabled/vypnuto)")

                            
                        # Přidáno: Automatická (plošná) synchronizace seriálů (JSON <-> SQL) při vstupu do doplňku
                        try:
                            from resources.lib.series import series_manager
                            profile_path = xbmcvfs.translatePath(fresh_addon.getAddonInfo('profile'))
                            sm = series_manager.SeriesManager(fresh_addon, profile_path)
                            log.info("Spouštím plošnou synchronizaci seriálů při vstupu do doplňku")
                            sm.sync_series_with_sql()
                        except Exception as e:
                            log.error(f"ERROR in enter-plugin series sync: {e}")
                            
                    except Exception as e:
                        log.error(f"ERROR in enter-plugin sync: {e}")

                # Uživatel právě OPUSTIL UI doplňku
                elif in_plugin_prev and not in_plugin_now:
                    try:
                        from resources.lib.utils.cloud_sync import CloudSync
                        fresh_addon = xbmcaddon.Addon('plugin.video.mmirousek_v3')
                        cs_exit = CloudSync(fresh_addon)
                        lock_active_exit = (fresh_addon.getSetting('trakt_payload_locked') == 'true')
                        playing_now = xbmc.Player().isPlaying()
                        playback_starting = (time.time() - _last_playback_start_time) < 15
                        
                        # ✅ FIX: Podobný guard jako u vstupu + ochrana proti EXIT syncu během scrobblingu
                        playback_stopping = (time.time() - _last_playback_stop_time) < 5
                        if lock_active_exit:
                            log.info("Auto-sync při OPUŠTĚNÍ ignorován (aktivní scrobble lock)")
                        elif playing_now:
                            log.info("Auto-sync při OPUŠTĚNÍ ignorován (aktivní přehrávání)")
                        elif playback_starting:
                            log.info("Auto-sync při OPUŠTĚNÍ ignorován (guard po startu přehrávání)")
                        elif playback_stopping:
                            log.info(f"Auto-sync při OPUŠTĚNÍ ignorován (zastavování přehrávání – guard 5s)")
                        elif cs_exit.enabled and cs_exit.sync_on_exit:
                            log.info("Auto-sync při OPUŠTĚNÍ doplňku (nebo spuštění ext. aplikace) → sync_all()")
                            cs_exit.sync_all()
                        else:
                            log.info("Auto-sync při OPUŠTĚNÍ doplňku přeskočen (disabled/vypnuto)")
                    except Exception as e:
                        log.error(f"ERROR in exit-from-leave sync: {e}")

                in_plugin_prev = in_plugin_now
                
                # --- BACKGROUND OFFLINE SCANNER ---
                try:
                    from resources.lib.utils.offline_scanner import run_offline_scan
                    run_offline_scan()
                except Exception as e:
                    log.error(f"Error running offline scan from service: {e}")
                    
                # --- AUTO DOWNLOAD každých 5 minut ---
                now_ts = time.time()
                if now_ts - last_auto_check >= 300:  # 5 minut
                    last_auto_check = now_ts
                    enable_auto = __addon__.getSettingBool('enable_auto_download')
                    start_time = __addon__.getSetting('auto_download_start') or '22:00'
                    end_time   = __addon__.getSetting('auto_download_end')   or '06:00'
                    in_window  = in_time_window(start_time, end_time)

                    log.debug(f"AutoDownload enable={enable_auto}, window={start_time}-{end_time}, in_window={in_window}")

                    if not enable_auto:
                        if _is_auto_session():
                            log.info("AutoDownload Disable detected → clearing session")
                            _set_auto_session(False)
                    else:
                        if in_window:
                            if _any_pending() and not _any_downloading():
                                log.info("AutoDownload Starting queue (in window)")
                                xbmcgui.Dialog().notification("AutoDownload", "Automatické stahování zahájeno", xbmcgui.NOTIFICATION_INFO, 2500)
                                _set_auto_session(True)
                                start_all()
                        else:
                            if _is_auto_session() and _any_downloading():
                                log.info("AutoDownload Outside window → stopping auto session downloads")
                                stop_all_downloads()
                                xbmcgui.Dialog().notification("AutoDownload", "Stahování ukončeno mimo časové okno", xbmcgui.NOTIFICATION_WARNING, 2500)
                                _set_auto_session(False)
                            elif _is_auto_session():
                                log.debug("AutoDownload Outside window and no downloading → clearing session")
                                _set_auto_session(False)

                if monitor.waitForAbort(1):
                    break
            except Exception as e:
                log.warning(f'Tik chyba: {e}')

    finally:
        try:
            xbmcgui.Window(10000).setProperty('mm_scrobble_service_running', '')
        except Exception:
            pass
        log.info('##### SERVICE UKONČEN #####')
        
