
# -*- coding: utf-8 -*-
import os
import json
import hashlib
import xbmcvfs
import xbmcaddon
import xbmcgui
from urllib.parse import quote_plus
from resources.lib.utils.log_utils import get_logger

log = get_logger()

ADDON_ID = 'plugin.video.mmirousek_v3'
ADDON = xbmcaddon.Addon(ADDON_ID)
PROFILE = xbmcvfs.translatePath(ADDON.getAddonInfo('profile'))
ADDON_PATH = xbmcvfs.translatePath(ADDON.getAddonInfo('path'))

# --- Index pro M3U export (inkrementální) -----------------------------------
M3U_INDEX_JSON = os.path.join(PROFILE, 'playlist_index.json')


# ---------------------------------------------------------------------------
# Pomocné: notifikace, dirs, safe názvy
# ---------------------------------------------------------------------------
def _notify(msg: str, icon=xbmcgui.NOTIFICATION_INFO, ms: int = 3500):
    try:
        xbmcgui.Dialog().notification(ADDON.getAddonInfo('name'), msg, icon, ms)
    except Exception:
        pass


def _ensure_dir(path: str):
    if not xbmcvfs.exists(path):
        try:
            xbmcvfs.mkdirs(path)
        except Exception:
            try:
                os.makedirs(path, exist_ok=True)
            except Exception:
                pass


def _resolve_library_roots(notify_if_missing: bool = True):
    """
    Vrátí cílové kořeny pro export dle settings:
      - <library_folder>/KodiLibrary/Serialy
      - <library_folder>/KodiLibrary/Filmy
      - <library_folder>/KodiLibrary/m3uFilmy

    Pokud library_folder není nastavená, vrací (None, None, None)
    a volitelně zobrazí popup hlášku.
    """
    raw_folder = (ADDON.getSetting('library_folder') or '').strip()
    if not raw_folder:
        if notify_if_missing:
            _notify("Není nastavena složka pro Kodi knihovnu.", xbmcgui.NOTIFICATION_WARNING, 4500)
        return None, None, None

    try:
        user_base = xbmcvfs.translatePath(raw_folder)
    except Exception:
        user_base = raw_folder

    user_base = (user_base or '').strip()
    if not user_base:
        if notify_if_missing:
            _notify("Není nastavena složka pro Kodi knihovnu.", xbmcgui.NOTIFICATION_WARNING, 4500)
        return None, None, None

    kodi_library_root = os.path.join(user_base, 'KodiLibrary')
    series_root = os.path.join(kodi_library_root, 'Serialy')
    movies_root = os.path.join(kodi_library_root, 'Filmy')
    m3u_movies_root = os.path.join(kodi_library_root, 'm3uFilmy')
    return series_root, movies_root, m3u_movies_root


def _safe_name(s: str) -> str:
    if not s:
        return "unknown"
    safe = (s.replace('/', '-')
              .replace('\\', '-')
              .replace(':', '-')
              .replace('\n', '-')
              .replace('*', '-')
              .replace('?', '-')
              .replace('"', "'")
              .strip(" .\t\r\n"))
    return safe or "unknown"


def _sha1(s: str) -> str:
    return hashlib.sha1((s or '').encode('utf-8')).hexdigest()


def _series_name_variants(series_name: str):
    """Vrátí možné varianty názvu pro robustní lookup v SQLite."""
    raw = (series_name or '').strip()
    if not raw:
        return []
    variants = [
        raw,
        raw.replace('.json', ''),
        _safe_name(raw),
        raw.replace(':', '_').replace('?', '_'),
    ]
    out = []
    seen = set()
    for v in variants:
        key = (v or '').strip()
        if not key:
            continue
        low = key.lower()
        if low in seen:
            continue
        seen.add(low)
        out.append(key)
    return out


def _find_series_sql_by_name(series_name: str):
    """
    Najde seriál v SQLite tabulce series_data.
    Vrací tuple (virtual_path, data_dict) nebo (None, None).
    """
    try:
        from resources.lib.database.metadata_db import db
    except Exception:
        return None, None

    variants = _series_name_variants(series_name)
    if not variants:
        return None, None

    # 1) Přímé lookupy přes známé klíče
    try:
        for candidate in variants:
            data = db.get_series_data(candidate)
            if isinstance(data, dict):
                return f"sqlite://series_data/{candidate}", data
    except Exception:
        pass

    # 2) Fallback: projít tabulku a porovnat display name i safe name
    try:
        if not getattr(db, 'conn', None):
            return None, None

        wanted_lc = set(v.lower() for v in variants)
        cursor = db.conn.execute("SELECT series_name, json_data FROM series_data")
        for row in cursor.fetchall():
            series_key = (row[0] or '').strip()
            raw_json = row[1]

            if series_key and series_key.lower() in wanted_lc:
                try:
                    data = json.loads(raw_json)
                    if isinstance(data, dict):
                        return f"sqlite://series_data/{series_key}", data
                except Exception:
                    continue

            try:
                data = json.loads(raw_json)
            except Exception:
                continue
            if not isinstance(data, dict):
                continue

            display = (data.get('name') or '').strip()
            if not display:
                continue

            display_variants = {
                display.lower(),
                _safe_name(display).lower(),
                display.replace(':', '_').replace('?', '_').lower(),
            }
            if wanted_lc.intersection(display_variants):
                return f"sqlite://series_data/{series_key or display}", data
    except Exception:
        return None, None

    return None, None


def _export_series_data_to_library(series_name: str, data: dict, series_root: str, only_season: str = None) -> int:
    """Exportuje jeden seriál (volitelně pouze jednu sezónu). Vrací počet vytvořených .strm souborů."""
    if not isinstance(data, dict):
        return 0

    _ensure_dir(series_root)
    display_name = data.get('name') or series_name
    series_folder = os.path.join(series_root, _safe_name(display_name))
    _ensure_dir(series_folder)

    count_files = 0
    seasons = data.get('seasons', {})
    for season_key, episodes in (seasons.items() if isinstance(seasons, dict) else []):
        if only_season is not None and str(season_key) != str(only_season):
            continue

        season_folder = os.path.join(series_folder, f"Sezona {season_key}")
        _ensure_dir(season_folder)

        for ep_key, ep_data in (episodes.items() if isinstance(episodes, dict) else []):
            ep_title = ep_data.get('name') or ep_data.get('title') or f"Epizoda {ep_key}"
            strm_filename = f"S{int(season_key):02d}E{int(ep_key):02d} - {_safe_name(ep_title)}.strm"
            strm_path = os.path.join(season_folder, strm_filename)

            plugin_url = (
                f"plugin://{ADDON_ID}/?action=play"
                f"&select=1&series_name={quote_plus(display_name)}"
                f"&season={quote_plus(str(season_key))}"
                f"&episode={quote_plus(str(ep_key))}"
            )
            with xbmcvfs.File(strm_path, 'w') as sf:
                sf.write(plugin_url)
            count_files += 1

    return count_files


# =============================================================================
# 0) Chytrý výběr cesty k playlistu M3U
# =============================================================================
def _get_playlist_path() -> str:
    """
    Vrátí existující cestu k playlistu M3U v pořadí:
      1) Nastavení addonu (playlist_path) — pouze, pokud soubor existuje.
      2) Fallback v addonu: resources/media/playlist.m3u — pokud existuje.
      3) Kodi profily: special://profile/playlist.m3u, special://home/userdata/playlist.m3u — první existující.
    Pokud nic nenajde, vrátí původní hodnotu ze Settings (kvůli diagnostice).
    V logu vypíše, kterou variantu použil.
    """
    # 1) Uživatelské nastavení
    user_path_raw = ADDON.getSetting('playlist_path') or ''
    if user_path_raw:
        try:
            user_path = xbmcvfs.translatePath(user_path_raw)
        except Exception:
            user_path = user_path_raw
        try:
            if xbmcvfs.exists(user_path):
                log.info(f"Using playlist from settings: {user_path}")
                return user_path
            else:
                log.warning(f"Settings path not found, will fallback: {user_path}")
        except Exception:
            log.warning("Failed to probe settings path, will fallback")

    # 2) Fallback uvnitř addonu
    try:
        fallback = xbmcvfs.translatePath(ADDON_PATH + "/resources/media/playlist.m3u")
        if xbmcvfs.exists(fallback):
            log.info(f"Using fallback playlist: {fallback}")
            return fallback
        else:
            log.warning(f"Fallback file missing: {fallback}")
    except Exception:
        log.warning("Failed to resolve addon fallback path")

    # 3) Běžné umístění v Kodi profilu
    candidates = [
        "special://profile/playlist.m3u",
        "special://home/userdata/playlist.m3u",
    ]
    for cand in candidates:
        try:
            p = xbmcvfs.translatePath(cand)
        except Exception:
            p = cand
        try:
            if xbmcvfs.exists(p):
                log.info(f"Using profile candidate: {p}")
                return p
        except Exception:
            pass

    log.warning("No valid playlist found. Returning last known settings/raw path.")
    return user_path_raw or ''


# =============================================================================
# 1) Export SERIÁLŮ → .strm (Varianta A: action=play&select=1)
# =============================================================================
def export_series_to_kodi_library():
    """
    Projde všechny záznamy v SQLite tabulce series_data a vytvoří .strm soubory (Seriály).
    Každý .strm: plugin://.../?action=play&select=1&series_name=...&season=...&episode=...
    """
    try:
        from resources.lib.database.metadata_db import db

        series_root, _movies_root, _m3u_movies_root = _resolve_library_roots(notify_if_missing=True)
        if not series_root:
            return

        if not getattr(db, 'conn', None):
            _notify("Kodi knihovna (Seriály): DB není dostupná.", xbmcgui.NOTIFICATION_WARNING, 3500)
            return

        _ensure_dir(series_root)
        count_series = 0
        count_files = 0
        cursor = db.conn.execute("SELECT series_name, json_data FROM series_data")
        for series_key, raw_json in cursor.fetchall():
            try:
                data = json.loads(raw_json)
            except Exception:
                continue
            if not isinstance(data, dict):
                continue

            series_name = (data.get('name') or series_key or '').strip()
            if not series_name:
                continue

            exported = _export_series_data_to_library(series_name, data, series_root)
            count_files += exported
            count_series += 1

        _notify(f"Kodi knihovna (Seriály): {count_series} seriálů, {count_files} epizod.", xbmcgui.NOTIFICATION_INFO, 4000)
    except Exception as e:
        _notify(f"Kodi knihovna (Seriály) – chyba: {e}", xbmcgui.NOTIFICATION_ERROR, 5000)
        log.error(f"Failed to export series to Kodi library: {e}", exc_info=True)


def export_selected_series_to_kodi_library(series_name: str):
    """Exportuje pouze vybraný seriál do Kodi knihovny."""
    try:
        series_root, _movies_root, _m3u_movies_root = _resolve_library_roots(notify_if_missing=True)
        if not series_root:
            return

        source, data = _find_series_sql_by_name(series_name)
        if not source or not isinstance(data, dict):
            _notify("Export seriálu: data nenalezena.", xbmcgui.NOTIFICATION_WARNING, 3500)
            return

        exported = _export_series_data_to_library(series_name, data, series_root)
        name = data.get('name') or series_name
        _notify(f"Export seriálu hotov: {name} ({exported} ep.)", xbmcgui.NOTIFICATION_INFO, 3500)
    except Exception as e:
        _notify(f"Export seriálu – chyba: {e}", xbmcgui.NOTIFICATION_ERROR, 5000)
        log.error(f"Failed to export selected series '{series_name}': {e}", exc_info=True)


def export_selected_season_to_kodi_library(series_name: str, season: str):
    """Exportuje pouze vybranou sezónu seriálu do Kodi knihovny."""
    try:
        series_root, _movies_root, _m3u_movies_root = _resolve_library_roots(notify_if_missing=True)
        if not series_root:
            return

        source, data = _find_series_sql_by_name(series_name)
        if not source or not isinstance(data, dict):
            _notify("Export sezóny: data nenalezena.", xbmcgui.NOTIFICATION_WARNING, 3500)
            return

        exported = _export_series_data_to_library(series_name, data, series_root, only_season=str(season))
        name = data.get('name') or series_name
        _notify(f"Export sezóny hotov: {name} S{season} ({exported} ep.)", xbmcgui.NOTIFICATION_INFO, 3500)
    except Exception as e:
        _notify(f"Export sezóny – chyba: {e}", xbmcgui.NOTIFICATION_ERROR, 5000)
        log.error(f"Failed to export selected season '{series_name}' S{season}: {e}", exc_info=True)


# =============================================================================
# 2) Export FILMŮ z playlist.m3u → .strm (s podporou FORCE režimu)
# =============================================================================
def _load_m3u_index():
    try:
        if xbmcvfs.exists(M3U_INDEX_JSON):
            with xbmcvfs.File(M3U_INDEX_JSON, 'r') as f:
                return json.loads(f.read())
    except Exception as e:
        log.warning(f"Failed to load M3U index: {e}")
    return {"entries": {}, "playlist_hash": "", "playlist_mtime": 0}


def _save_m3u_index(idx: dict):
    try:
        with xbmcvfs.File(M3U_INDEX_JSON, 'w') as f:
            f.write(json.dumps(idx, ensure_ascii=False, indent=2))
    except Exception as e:
        log.error(f"Failed to save M3U index with xbmcvfs: {e}")
        try:
            with open(M3U_INDEX_JSON, 'w', encoding='utf-8') as f:
                json.dump(idx, f, ensure_ascii=False, indent=2)
        except Exception as e2:
            log.error(f"Failed to save M3U index with open(): {e2}")


def _read_text_file(path: str) -> str:
    try:
        with xbmcvfs.File(path, 'r') as f:
            return f.read()
    except Exception:
        try:
            with open(path, 'r', encoding='utf-8', errors='ignore') as f:
                return f.read()
        except Exception as e:
            log.error(f"Failed to read text file {path}: {e}")
            return ""


def _parse_m3u_entries(text: str):
    import re
    items = []
    if not text:
        return items
    lines = [l.strip() for l in text.replace('\r', '').split('\n') if l.strip()]
    i = 0
    while i < len(lines):
        line = lines[i]
        if line.startswith('#EXTINF'):
            try:
                title_part = line.split(',', 1)[1].strip()
            except Exception:
                title_part = "Unknown"
            ym = re.search(r'\((19\d{2}|20\d{2})\)', title_part)
            year = int(ym.group(1)) if ym else None
            title = _safe_name(title_part)

            url = None
            j = i + 1
            while j < len(lines):
                if not lines[j].startswith('#'):
                    url = lines[j].strip()
                    break
                j += 1

            if url:
                items.append({"title": title, "year": year, "url": url})
            i = j if j > i else i + 1
        else:
            i += 1
    return items


def _movie_folder_name(title: str, year: int = None) -> str:
    if year and 1900 <= int(year) <= 2099:
        return f"{title} ({int(year)})"
    return title


def _strm_path_for_movie(title: str, movies_root: str, year: int = None) -> str:
    folder = os.path.join(movies_root, _movie_folder_name(title, year))
    _ensure_dir(folder)
    return os.path.join(folder, f"{_safe_name(title)}.strm")


def _write_movie_strm(path: str, url: str) -> bool:
    plugin_url = (
        f"plugin://{ADDON_ID}/?action=play_m3u_stream"
        f"&m3u_url={quote_plus(url)}"
    )
    try:
        with xbmcvfs.File(path, 'w') as f:
            f.write(plugin_url)
        return True
    except Exception as e:
        log.warning(f"Failed to write strm file with xbmcvfs '{path}': {e}")
        try:
            with open(path, 'w', encoding='utf-8') as f:
                f.write(plugin_url)
            return True
        except Exception as e2:
            log.error(f"Failed to write strm file with open() '{path}': {e2}")
            return False


# --- FORCE přepínač ----------------------------------------------------------
def _is_force_m3u_export() -> bool:
    """
    Dočasný přepínač 'force' pro M3U export.
    - ADDON setting 'm3u_export_force' == 'true'  → zapne
    - NEBO existuje soubor PROFILE/force_m3u_export.flag → zapne
    """
    try:
        if (ADDON.getSetting('m3u_export_force') or '').lower() == 'true':
            return True
    except Exception:
        pass
    try:
        flag_path = os.path.join(PROFILE, 'force_m3u_export.flag')
        return xbmcvfs.exists(flag_path)
    except Exception:
        return False


def export_movies_from_m3u(force: bool = False):
    """
    Inkrementální export filmů z playlist.m3u do <library_folder>/KodiLibrary/m3uFilmy (.strm).
    Pokud je 'force' True nebo je aktivní _is_force_m3u_export(),
    provede export vždy (ignoruje index/změnu souboru).
    """
    _series_root, _movies_root, m3u_movies_root = _resolve_library_roots(notify_if_missing=True)
    if not m3u_movies_root:
        return

    _ensure_dir(m3u_movies_root)

    pl_path = _get_playlist_path()
    if not xbmcvfs.exists(pl_path):
        _notify(f"Playlist nenalezen: {pl_path}", xbmcgui.NOTIFICATION_WARNING)
        log.warning(f"M3U playlist not found at: {pl_path}")
        return

    text = _read_text_file(pl_path)

    # mtime + hash (pro běžný režim)
    try:
        st = xbmcvfs.Stat(pl_path)
        mtime = int(getattr(st, "st_mtime", lambda: 0)() if callable(getattr(st, "st_mtime", None)) else 0)
    except Exception:
        try:
            mtime = int(os.path.getmtime(pl_path))
        except Exception:
            mtime = 0
    pl_hash = _sha1(text)

    # načti index
    idx = _load_m3u_index()

    # dočasný FORCE přepínač (runtime)
    force_runtime = bool(force) or _is_force_m3u_export()

    # je playlist změněný?
    changed = force_runtime or (idx.get("playlist_hash") != pl_hash or int(idx.get("playlist_mtime", 0)) != mtime)

    entries = _parse_m3u_entries(text)
    if not entries:
        _notify("Playlist je prázdný nebo nečitelný.", xbmcgui.NOTIFICATION_WARNING)
        log.warning("M3U playlist is empty or could not be parsed.")
        return

    exported = 0
    idx_entries = idx.get("entries", {})

    for item in entries:
        url = item["url"]
        title = item["title"]
        year = item.get("year")
        key = _sha1(url)

        if not force_runtime:
            # běžný režim: když položka už v indexu je a playlist se nezměnil → přeskoč
            if key in idx_entries and not changed:
                continue
            # ochrana proti duplicitnímu přidání téže položky v rámci jednoho běhu
            if key in idx_entries:
                continue

        strm_path = _strm_path_for_movie(title, m3u_movies_root, year)

        # zápis .strm vždy přepíše (xbmcvfs.File(..., 'w'))
        ok = _write_movie_strm(strm_path, url)
        if not ok:
            # fallback jméno s hash prefixem; pokus o zápis znovu
            strm_path = _strm_path_for_movie(f"{title} - {key[:6]}", m3u_movies_root, year)
            _write_movie_strm(strm_path, url)

        # aktualizuj index (i v force režimu – ať máme poslední umístění .strm)
        idx_entries[key] = {
            "title": title,
            "year": year,
            "strm_path": strm_path,
            "url": url
        }
        exported += 1

    # ulož index + metadata playlistu
    idx["entries"] = idx_entries
    idx["playlist_mtime"] = mtime
    idx["playlist_hash"] = pl_hash
    _save_m3u_index(idx)

    if exported > 0:
        mode_txt = " (FORCE)" if force_runtime else ""
        _notify(f"M3U → knihovna: +{exported} filmů{mode_txt}", xbmcgui.NOTIFICATION_INFO)
        log.info(f"Exported {exported} new movies from M3U to library. Mode: {'FORCE' if force_runtime else 'INCREMENTAL'}")
    else:
        _notify("Playlist beze změny (žádné nové filmy).", xbmcgui.NOTIFICATION_INFO)
        log.info("M3U export finished. No new movies found.")
