# -*- coding: utf-8 -*-
import xbmcaddon
import xbmcvfs
import time
import os
import re
from resources.lib.database.metadata_db import db
from resources.lib.utils.log_utils import get_logger

log = get_logger()
ADDON_ID = 'plugin.video.mmirousek_v3'

_last_scan_time = 0


def _parse_season_dir_name(dirname: str):
    from resources.lib.down.offline_cache_utils import parse_season_dir_name
    return parse_season_dir_name(dirname)

# =============================================================================
# [DEBUG-SCAN] ZAČÁTEK – DOČASNÉ PODROBNÉ LOGOVÁNÍ SCANNERU
# Po odladění SMAŽ všechny bloky označené "[DEBUG-SCAN]" a vrať funkci
# run_offline_scan() do původní tiché podoby.
# =============================================================================
_DEBUG_SCAN = False  # [DEBUG-SCAN] master vypínač – nastav False pro utišení


def _log_scan(msg: str):
    """Trvalé INFO logování scanu / zápisu offline_cache (grep: OfflineScanner)."""
    log.info(f"[OfflineScanner] {msg}")


def _dbg(msg: str):
    """[DEBUG-SCAN] Logovací helper – píše na INFO úroveň, aby bylo vidět
    i bez zapnutého debug logu v Kodi. Prefix [OfflineScanner][DBG] je
    snadno grepovatelný: `grep "OfflineScanner\\[DBG\\]" kodi.log`.
    """
    if _DEBUG_SCAN:
        log.info(f"[OfflineScanner][DBG] {msg}")
# =============================================================================
# [DEBUG-SCAN] KONEC hlavičky – hlavní tělo logování viz níže uvnitř funkce.
# =============================================================================


def run_offline_scan(force=False):
    global _last_scan_time
    now = time.time()

    # Skenujeme každých 5 minut nebo pokud je explicitně zavoláno (např. po smazání souboru)
    if not force and (now - _last_scan_time < 3600):
        # --- [DEBUG-SCAN] ---
        _dbg(f"Skip běhu – throttle ({int(now - _last_scan_time)}s od posledního scanu, force={force})")
        # --- [DEBUG-SCAN] konec ---
        return

    # --- [DEBUG-SCAN] ---
    _t_start = time.time()
    _dbg(f"=== START scan (force={force}, last_scan_time={_last_scan_time}) ===")
    _stats = {
        'dirs_total': 0,
        'dirs_skipped_listdir_err': 0,
        'season_dirs_total': 0,
        'season_dirs_skipped_regex': 0,
        'season_dirs_skipped_listdir_err': 0,
        'files_total': 0,
        'files_skipped_ext': 0,
        'files_skipped_regex': 0,
        'files_matched': 0,
        'stat_errors': 0,
        'tmdb_mapped': 0,
        'tmdb_not_mapped': 0,
        'series_with_items': 0,
        'series_without_items': 0,
        'removed_from_cache': 0,
    }
    # --- [DEBUG-SCAN] konec ---

    try:
        from resources.lib.down.offline_cache_utils import (
            resolve_dfolder_path,
            offline_cache_key_for_disk_folder,
            resolve_offline_cache_key_for_disk_folder,
            build_disk_folder_to_storage_key_index,
            merge_offline_scan_items,
        )
        addon = xbmcaddon.Addon(ADDON_ID)
        dfolder = resolve_dfolder_path(addon)
        raw_dfolder = (addon.getSetting('dfolder') or '').strip()
        raw_slot = addon.getSetting('dfolder_slot') or ''
        if not dfolder:
            _log_scan("ABORT – nastavení dfolder je prázdné "
                      f"(raw='{raw_dfolder}', slot='{raw_slot}')")
            # --- [DEBUG-SCAN] ---
            _dbg("ABORT – nastavení 'dfolder' je prázdné")
            # --- [DEBUG-SCAN] konec ---
            return

        if not xbmcvfs.exists(dfolder):
            _log_scan(f"ABORT – dfolder neexistuje: resolved='{dfolder}' raw='{raw_dfolder}'")
            # --- [DEBUG-SCAN] ---
            _dbg(f"ABORT – dfolder neexistuje: '{dfolder}'")
            # --- [DEBUG-SCAN] konec ---
            return

        _log_scan(
            f"START force={force} | raw_dfolder='{raw_dfolder}' | "
            f"resolved_dfolder='{dfolder}' | slot='{raw_slot}'"
        )
        log.debug("[OfflineScanner] Spouštím scan offline souborů na pozadí")
        # --- [DEBUG-SCAN] ---
        _dbg(f"dfolder='{dfolder}'")
        # --- [DEBUG-SCAN] konec ---
        _last_scan_time = now

        folder_index = build_disk_folder_to_storage_key_index()
        if folder_index:
            preview = ', '.join(f"{k!r}->{v!r}" for k, v in list(folder_index.items())[:15])
            extra = f" (+{len(folder_index) - 15} dalších)" if len(folder_index) > 15 else ""
            _log_scan(f"folder_index ({len(folder_index)}): {preview}{extra}")
        else:
            _log_scan("folder_index je prázdný (žádné series_data v DB?)")

        cache_data = {}
        dirs, files = xbmcvfs.listdir(dfolder)

        _log_scan(
            f"listdir('{dfolder}'): {len(dirs)} podsložek, {len(files)} souborů v kořeni"
        )
        if dirs:
            _log_scan(f"  podsložky: {dirs}")
        if files:
            _log_scan(f"  soubory v kořeni (ignorovány): {files[:20]}")

        # --- [DEBUG-SCAN] ---
        _stats['dirs_total'] = len(dirs)
        # --- [DEBUG-SCAN] konec ---

        existing_cache = db.get_offline_cache_all()
        if existing_cache:
            _log_scan(
                f"existující offline_cache před scanem: "
                f"{len(existing_cache)} klíčů -> {sorted(existing_cache.keys())}"
            )

        if not dirs and existing_cache:
            log.warning(
                "[OfflineScanner] dfolder neobsahuje žádné podsložky – "
                "offline_cache se nemaže (ochrana před falešně prázdným scanem)"
            )
            # --- [DEBUG-SCAN] ---
            _dbg("ABORT – 0 podsložek, existující cache zachována")
            # --- [DEBUG-SCAN] konec ---
            return

        for d in dirs:
            # --- [DEBUG-SCAN] ---
            _dbg(f"--- Zpracovávám složku seriálu: '{d}'")
            # --- [DEBUG-SCAN] konec ---

            cache_key = offline_cache_key_for_disk_folder(d)
            storage_key = resolve_offline_cache_key_for_disk_folder(d, folder_index)
            _log_scan(
                f"SLOŽKA disk='{d}' | cache_key='{cache_key}' | "
                f"storage_key='{storage_key}' | shoda={cache_key == storage_key}"
            )
            if re.match(r'^tmdb_\d+$', d, re.IGNORECASE):
                if storage_key != cache_key:
                    _stats['tmdb_mapped'] += 1
                    _dbg(f"    tmdb složka '{d}' -> storage '{storage_key}', cache klíč '{cache_key}'")
                elif d not in folder_index:
                    _stats['tmdb_not_mapped'] += 1
                    _dbg(f"    tmdb mapping FAIL: '{d}' – seriál není v series_data")
            else:
                if storage_key != cache_key:
                    _dbg(f"    složka '{d}' -> cache klíč '{cache_key}' (storage '{storage_key}')")
                else:
                    _dbg(f"    cache klíč '{cache_key}'")

            series_path = os.path.join(dfolder, d).replace('\\', '/')
            if not series_path.endswith('/'):
                series_path += '/'
            _log_scan(f"  series_path='{series_path}'")

            try:
                season_dirs, _ = xbmcvfs.listdir(series_path)
            except Exception as _e_listdir:
                _stats['dirs_skipped_listdir_err'] += 1
                _log_scan(f"  SKIP listdir selhal: {_e_listdir}")
                _dbg(f"    SKIP – listdir selhal na '{series_path}': {_e_listdir}")
                continue

            _log_scan(f"  sezóny v '{d}': {season_dirs}")
            _dbg(f"    Podsložky v seriálu: {season_dirs}")

            items = []

            for sd in season_dirs:
                # --- [DEBUG-SCAN] ---
                _stats['season_dirs_total'] += 1
                # --- [DEBUG-SCAN] konec ---
                season_num = _parse_season_dir_name(sd)
                if season_num is None:
                    # --- [DEBUG-SCAN] ---
                    _stats['season_dirs_skipped_regex'] += 1
                    _dbg(f"    SKIP sezóna '{sd}' – neodpovídá regexu sezóny")
                    # --- [DEBUG-SCAN] konec ---
                    continue

                season_path = os.path.join(series_path, sd).replace('\\', '/')
                if not season_path.endswith('/'):
                    season_path += '/'

                try:
                    _, ep_files = xbmcvfs.listdir(season_path)
                except Exception as _e_listdir2:
                    # --- [DEBUG-SCAN] ---
                    _stats['season_dirs_skipped_listdir_err'] += 1
                    _dbg(f"    SKIP sezóna '{sd}' – listdir selhal na '{season_path}': {_e_listdir2}")
                    # --- [DEBUG-SCAN] konec ---
                    continue

                # --- [DEBUG-SCAN] ---
                _dbg(f"    Sezóna '{sd}' (num={season_num}): {len(ep_files)} souborů")
                _matched_in_season = 0
                # --- [DEBUG-SCAN] konec ---

                for ef in ep_files:
                    # --- [DEBUG-SCAN] ---
                    _stats['files_total'] += 1
                    # --- [DEBUG-SCAN] konec ---
                    if ef.lower().endswith(('.mp4', '.mkv', '.avi', '.ts')):
                        # Očekáváme "Název S01E03.mp4" nebo podobný formát
                        ep_match = re.search(r'(?i)S\d+E(\d+)', ef)
                        if ep_match:
                            ep_num = int(ep_match.group(1))
                            ep_path = os.path.join(season_path, ef).replace('\\', '/')

                            try:
                                st = xbmcvfs.Stat(ep_path)
                                size = st.st_size() if st else 0
                            except Exception as _e_stat:
                                size = 0
                                # --- [DEBUG-SCAN] ---
                                _stats['stat_errors'] += 1
                                _dbg(f"        STAT FAIL '{ef}': {_e_stat}")
                                # --- [DEBUG-SCAN] konec ---

                            items.append({
                                'season': season_num,
                                'episode': ep_num,
                                'path': ep_path,
                                'size': size
                            })
                            if _matched_in_season < 3:
                                _log_scan(
                                    f"  MATCH S{season_num:02d}E{ep_num:02d} "
                                    f"file='{ef}' size={size} path='{ep_path}'"
                                )
                            # --- [DEBUG-SCAN] ---
                            _stats['files_matched'] += 1
                            _matched_in_season += 1
                            _dbg(f"        MATCH S{season_num:02d}E{ep_num:02d} – '{ef}' ({size} B)")
                            # --- [DEBUG-SCAN] konec ---
                        else:
                            # --- [DEBUG-SCAN] ---
                            _stats['files_skipped_regex'] += 1
                            _dbg(f"        SKIP soubor '{ef}' – neobsahuje pattern SxxExx")
                            # --- [DEBUG-SCAN] konec ---
                    else:
                        # --- [DEBUG-SCAN] ---
                        _stats['files_skipped_ext'] += 1
                        _dbg(f"        SKIP soubor '{ef}' – nepodporovaná přípona (povoleno: mp4/mkv/avi/ts)")
                        # --- [DEBUG-SCAN] konec ---

                # --- [DEBUG-SCAN] ---
                _dbg(f"    Sezóna '{sd}' dokončena – nalezeno {_matched_in_season} epizod")
                # --- [DEBUG-SCAN] konec ---

            if items:
                prior = cache_data.get(cache_key, [])
                cache_data[cache_key] = merge_offline_scan_items(prior, items)
            merged_items = cache_data.get(cache_key, [])
            if merged_items:
                _stats['series_with_items'] += 1
                _seasons_set = sorted({it['season'] for it in merged_items})
                _log_scan(
                    f"  SHRNUTÍ disk='{d}' -> cache_key='{cache_key}': "
                    f"{len(merged_items)} epizod, sezóny {_seasons_set}"
                )
                if len(merged_items) > 3:
                    _log_scan(
                        f"  ... +{len(merged_items) - 3} dalších epizod "
                        f"(v logu jen první 3 MATCH řádky)"
                    )
            else:
                _stats['series_without_items'] += 1
                _log_scan(f"  SHRNUTÍ disk='{d}' -> cache_key='{cache_key}': 0 epizod")
            # --- [DEBUG-SCAN] ---
            _dbg(
                f"    Seriál '{d}' -> cache klíč '{cache_key}': "
                f"{len(merged_items)} epizod"
            )
            # --- [DEBUG-SCAN] konec ---

        # Uložíme aktualizovaná data seriál po seriálu
        active_keys_with_items = set()
        _log_scan(f"ZÁPIS DO DB: {len(cache_data)} klíčů v cache_data")
        for s_name, s_items in cache_data.items():
            if s_items:
                _log_scan(
                    f"[DB] save_offline_cache_items(series_name='{s_name}', "
                    f"episodes={len(s_items)})"
                )
                for it in s_items[:8]:
                    _log_scan(
                        f"[DB]   INSERT series_name='{s_name}' "
                        f"S{int(it.get('season', 0)):02d}"
                        f"E{int(it.get('episode', 0)):02d} "
                        f"path='{it.get('path', '')}' "
                        f"size={it.get('size', 0)}"
                    )
                if len(s_items) > 8:
                    _log_scan(f"[DB]   ... +{len(s_items) - 8} dalších řádků")
                db.save_offline_cache_items(s_name, s_items)
                active_keys_with_items.add(s_name)
                _dbg(f"SAVE offline_cache: klíč '{s_name}' = {len(s_items)} epizod")
            else:
                _log_scan(f"[DB] SKIP prázdný klíč '{s_name}' (nic se neukládá)")

        if not active_keys_with_items and existing_cache and _stats['dirs_total'] > 0:
            log.warning(
                "[OfflineScanner] Nalezeny složky seriálů, ale 0 epizod – "
                "offline_cache se nemaže (zkontrolujte strukturu Sezona N / SxxExx)"
            )
            # --- [DEBUG-SCAN] ---
            _dbg("ABORT save/cleanup – 0 epizod při nenulovém počtu složek")
            # --- [DEBUG-SCAN] konec ---
            return

        # Odstraníme z cache seriály, které už na disku nejsou
        for existing_series in existing_cache.keys():
            if existing_series not in active_keys_with_items:
                _log_scan(f"[DB] DELETE offline_cache WHERE series_name='{existing_series}'")
                db.clear_offline_cache_for_series(existing_series)
                # --- [DEBUG-SCAN] ---
                _stats['removed_from_cache'] += 1
                _dbg(f"REMOVE z offline_cache: klíč '{existing_series}' už není na disku")
                # --- [DEBUG-SCAN] konec ---

        log.info(
            f"[OfflineScanner] Dokončen scan: {len(active_keys_with_items)} seriálů, "
            f"{sum(len(cache_data[k]) for k in active_keys_with_items)} epizod | "
            f"DB klíče: {sorted(active_keys_with_items)}"
        )
        # --- [DEBUG-SCAN] ---
        _dbg(
            "=== SUMMARY === "
            f"trvání={time.time() - _t_start:.2f}s | "
            f"složek={_stats['dirs_total']} "
            f"(listdir_err={_stats['dirs_skipped_listdir_err']}) | "
            f"tmdb mapped={_stats['tmdb_mapped']}/not={_stats['tmdb_not_mapped']} | "
            f"sezóny total={_stats['season_dirs_total']} "
            f"(skip regex={_stats['season_dirs_skipped_regex']}, listdir_err={_stats['season_dirs_skipped_listdir_err']}) | "
            f"soubory total={_stats['files_total']} "
            f"(match={_stats['files_matched']}, skip ext={_stats['files_skipped_ext']}, skip regex={_stats['files_skipped_regex']}) | "
            f"stat_err={_stats['stat_errors']} | "
            f"seriály s_itemy={_stats['series_with_items']}/prázdné={_stats['series_without_items']} | "
            f"odstraněno z cache={_stats['removed_from_cache']}"
        )
        _dbg("=== END scan ===")
        # --- [DEBUG-SCAN] konec ---

    except Exception as e:
        log.error(f"[OfflineScanner] Chyba při skenování offline souborů: {e}")
        # --- [DEBUG-SCAN] ---
        import traceback
        _dbg(f"EXCEPTION: {e}\n{traceback.format_exc()}")
        # --- [DEBUG-SCAN] konec ---
