# -*- coding: utf-8 -*-
"""
UI utilitky pro Kodi doplněk (plugin.video.mmirousek_v3):
- icons_path: základní cesta k ikonám v doplňku (včetně podsložek).
- pick_icon: výběr ikony podle názvu souboru s fallbackem na default Kodi.
- pick_icon_path: totéž, ale zadává se přímo addon_path (pro moduly bez Addon instance).
- add_menu_item: jednotné vytváření položek (label + plot + art + URL).

Použitelné z sm3_entry.py, tmdb_kodi.py i tvprogram.py.
"""

from __future__ import annotations
import os
from functools import lru_cache

try:
    from xbmcvfs import translatePath
except Exception:
    from xbmc import translatePath

import xbmcgui
import xbmcplugin
import xbmcvfs
import xbmc
import sys
from urllib.parse import quote, parse_qs, unquote
from typing import Optional, Tuple
from resources.lib.database.metadata_db import db
import time
import re
import unicodedata
from datetime import datetime
from resources.lib.utils.log_utils import get_logger

log = get_logger()

def icons_path(addon, *subdirs) -> str:
    """Vrátí absolutní cestu do resources/media/icons[/subdirs...]."""
    addon_path = translatePath(addon.getAddonInfo('path'))
    parts = [addon_path, 'resources', 'media', 'icons'] + list(subdirs)
    return os.path.join(*parts)


@lru_cache(maxsize=512)
def _icon_file_exists_normpath(full_path: str) -> bool:
    """Jedno I/O na cestu; opakované volání pick_icon v menu (ARCHITECTURE bod 5)."""
    try:
        return os.path.exists(full_path)
    except Exception:
        return False


def pick_icon(addon, file_name: str | None, kodi_fallback: str = 'DefaultFolder.png', *subdirs) -> str:
    """
    Vrátí plnou cestu k ikoně resources/media/icons[/subdirs]/<file_name>, pokud existuje.
    Jinak vrátí defaultní Kodi ikonu (kodi_fallback).
    Použití tam, kde je k dispozici objekt Addon.
    """
    if file_name:
        base = icons_path(addon, *subdirs)
        full = os.path.normpath(os.path.join(base, file_name))
        if _icon_file_exists_normpath(full):
            return full
    return kodi_fallback

def pick_icon_path(addon_path: str, file_name: str | None, kodi_fallback: str = 'DefaultFolder.png', *subdirs) -> str:
    """
    Stejné jako pick_icon(), ale bere přímo addon_path.
    Praktické v modulech, které mají jen cesty (např. tvprogram.py).
    """
    if file_name:
        base = os.path.join(addon_path, 'resources', 'media', 'icons', *subdirs)
        full = os.path.normpath(os.path.join(base, file_name))
        if _icon_file_exists_normpath(full):
            return full
    return kodi_fallback


# resources/lib/ui_utils.py

import xbmcaddon  # ← doplň, pokud ještě není

def make_static_item(label: str,
                     plot: str,
                     addon: xbmcaddon.Addon = None,
                     icon_name: str = None,
                     default_icon: str = 'DefaultFolder.png',
                     extra_art: dict = None,
                     info_labels: dict = None) -> xbmcgui.ListItem:
    """
    Vytvoří sjednocený ListItem pro statické menu položky:
      - label: titulek položky
      - plot: víceřádkový popis (použij \n pro zalomení)
      - icon_name: název souboru ikony v resources/media/icons (např. 'search.png');
                   pokud None → použije se default_icon
      - default_icon: Kodi fallback (např. 'DefaultAddonsSearch.png')
      - extra_art: volitelně doplní 'poster', 'fanart', 'thumb' apod. (dict)
      - info_labels: volitelný dict s dalšími Video infoLabels (title/genre/year…)
    """
    addon = addon or xbmcaddon.Addon()
    li = xbmcgui.ListItem(label=label)

    icon_file = (icon_name or '').strip()
    icon_final = pick_icon(addon, icon_file, default_icon) if icon_file else default_icon

    # Artwork – přidáme fanart, aby Estuary nepoužil fallback
    art = {
        'icon': icon_final,
        'thumb': icon_final,
        'poster': icon_final,
        'fanart': icon_final  # klíčové pro Estuary
    }
    if isinstance(extra_art, dict):
        for k, v in extra_art.items():
            if v:
                art[k] = v
    li.setArt(art)

    info = {'title': label, 'plot': (plot or '')}
    if isinstance(info_labels, dict):
        info.update({k: v for k, v in info_labels.items() if v is not None})
    tag = li.getVideoInfoTag()
    title = info.get('title')
    plot_text = info.get('plot')
    if title:
        tag.setTitle(str(title))
    if plot_text:
        tag.setPlot(str(plot_text))

    return li

def add_menu_item(
    handle: int,
    build_url_fn,
    label: str,
    plot: str,
    action: str,
    art_icon: str | None = None,
    is_folder: bool = True,
    **params
) -> None:
    """
    Vytvoří ListItem se sjednoceným plotem a artworkem a přidá jej do adresáře.
    - build_url_fn: funkce pro sestavení URL. Podporuje 2 signatury:
        a) build_url_fn(dict)           # např. tmdb_kodi.build_url(query)
        b) build_url_fn(**kwargs)       # např. sm3_entry.get_url(**kwargs)
    - action: hodnota parametru 'action' v URL.
    """
    li = xbmcgui.ListItem(label=label)
    tag = li.getVideoInfoTag()
    tag.setTitle(label)
    if plot:
        tag.setPlot(plot)
    if art_icon:
        li.setArt({'icon': art_icon, 'thumb': art_icon})

    # Vytvoř parametrický dict pro URL
    url_params = {'action': action, **params}

    # Podpora obou signatur build_url_fn
    try:
        # 1) build_url_fn(dict)
        url = build_url_fn(url_params)
    except TypeError:
        # 2) build_url_fn(**kwargs)
        url = build_url_fn(**url_params)

    xbmcplugin.addDirectoryItem(handle, url, li, isFolder=is_folder)

# --- UI helpery (společné) ----------------------------------------------------




# ---------------------------------------------------------------------------
# File & Path Utilities (nové)
# ---------------------------------------------------------------------------
import re

def clean_filename(name: str) -> str:
    """
    Očistí název souboru od zakázaných znaků a trailing teček/whitespace.
    Používá se pro stahování filmů/epizod i offline detekci.
    """
    if not name:
        return "download"
    safe = re.sub(r'[\\\/:*?"<>|\n]', '_', str(name))
    return safe.rstrip('. ').strip() or "download"

# ---------------------------------------------------------------------------
# Download Control Utilities
# ---------------------------------------------------------------------------
import xbmcgui

def reset_cancel_flags():
    """Resetuje všechny globální cancel flagy (mm_cancel_download, mm_cancel_download_all)."""
    win = xbmcgui.Window(10000)
    win.setProperty('mm_cancel_download', '0')
    win.setProperty('mm_cancel_download_all', '0')

def set_cancel_flags():
    """Nastaví globální cancel flagy na TRUE."""
    win = xbmcgui.Window(10000)
    win.setProperty('mm_cancel_download', '1')
    win.setProperty('mm_cancel_download_all', '1')

def is_cancel_requested() -> bool:
    """Vrátí True, pokud je aktivní cancel pro transfer nebo all."""
    win = xbmcgui.Window(10000)
    return (win.getProperty('mm_cancel_download') == '1' or win.getProperty('mm_cancel_download_all') == '1')


# ---------------------------------------------------------------------------
# File System Utilities (nové)
# ---------------------------------------------------------------------------

def path_exists(p: str) -> bool:
    """
    Bezpečně ověří existenci cesty: preferuje Kodi VFS (xbmcvfs), fallback na OS.
    Funguje pro soubory i složky, včetně 'special://' cest.
    """
    if not p:
        return False
    try:
        # xbmcvfs.exists vyžaduje trailing '/' pro složky; pro univerzalitu zkusíme obě varianty
        if xbmcvfs.exists(p):
            return True
        if p.endswith('/'):
            return xbmcvfs.exists(p[:-1])
        else:
            return xbmcvfs.exists(p + '/')
    except Exception:
        pass
    try:
        return os.path.exists(p) or os.path.isdir(p)
    except Exception:
        return False


def listdir_safe(p: str) -> list:
    """
    Bezpečné vypsání souborů v cestě (jen jména položek).
    Preferuje xbmcvfs.listdir, fallback na os.listdir.
    Při chybě vrací [].
    """
    if not p:
        return []
    try:
        dirs, files = xbmcvfs.listdir(p)
        # sjednotíme návrat: zajímají nás soubory/jména; Kodi vrací separátně dirs vs files
        return list(files) + list(dirs)
    except Exception:
        pass
    try:
        return os.listdir(p)
    except Exception:
        return []
# --- ADD: Folder Utilities ---

def ensure_folder(path: str) -> None:
    """
    Bezpečně vytvoří adresář (přes real path z xbmcvfs.translatePath).
    1:1 náhrada původního _ensure_folder v legacy search modulu.
    """
    if not path:
        return
    real = xbmcvfs.translatePath(path)
    try:
        os.makedirs(real, exist_ok=True)
    except Exception as e:
        log.warning(f"cannot create folder {real}: {e}")


# --- ADD: Target Path Builder ---
from .ui_utils import clean_filename  # pokud je soubor samostatný, import není nutný; nebo použij přímo local name

def make_target_path(addon, name: str) -> str:
    """
    Sestaví cílový target_path z nastavení dfolder + clean_filename(name) + zachování přípony.
    1:1 náhrada původního _make_target_path (bez závislosti na kořenových globálech doplňku).
    """
    try:
        dfolder = addon.getSetting('dfolder') or ''
    except Exception:
        dfolder = ''
    if not dfolder:
        # Bez dfolderu nebudeme cílovou cestu přidávat – queue_worker by skončil na error.
        return ''
    dest_real = xbmcvfs.translatePath(dfolder)
    ensure_folder(dest_real)
    base = clean_filename(name or '')
    _, ext = os.path.splitext(name or '')
    filename = base if not ext else (base + ext)
    return os.path.join(dest_real, filename)


def prompt_and_filter_list(action: str, query_key: str = 'title_filter', dialog_heading: str = 'Zadejte počáteční písmena') -> None:
    """
    Zobrazí klávesnici pro zadání textu a aktualizuje kontejner (list)
    s novým parametrem filtru.

    Args:
        action (str): Název akce pro volání v routeru (např. 'show_progress_watching').
        query_key (str): Klíč parametru, pod kterým bude filtr uložen (např. 'title_filter').
        dialog_heading (str): Text, který se zobrazí na klávesnici.
    """
    keyboard = xbmc.Keyboard('', dialog_heading)
    keyboard.doModal()

    if keyboard.isConfirmed():
        filter_text = keyboard.getText().strip()
        
        # Sestavíme URL pro aktualizaci kontejneru
        # sys.argv[0] je vždy cesta k addon.py, get_url() by mělo být dostupné
        # (pokud je get_url definováno v jiném modulu, je třeba ho sem importovat/definovat)
        
        # Použijeme přímou URL manipulaci, pokud get_url není dostupné
        
        base_url = sys.argv[0]
        params = f'?action={action}'

        if filter_text:
            # Přejdeme na hlavní menu s filtrem
            params += f'&{query_key}={quote(filter_text)}'
            
        xbmc.executebuiltin('Container.Update(%s%s)' % (base_url, params))


def get_filter_param(url: str, query_key: str = 'title_filter') -> Optional[str]:
    """
    Parsuje URL a vrací hodnotu filtru podle klíče.

    Args:
        url (str): Celá URL kontejneru, včetně parametrů.
        query_key (str): Klíč parametru filtru (např. 'title_filter').
        
    Returns:
        str | None: Hodnota filtru, nebo None.
    """
    try:
        # Zpracování URL parametrů
        query_params = parse_qs(url.split('?')[-1])
        filter_list = query_params.get(query_key, [None])
        
        if filter_list[0]:
            return unquote(filter_list[0])
        return None
    except Exception:
        return None

def toggle_watchlist(tmdb_id: int):
    """
    Přidá nebo odebere film s daným tmdb_id do/z Webshare Watchlistu
    pomocí timestampu v DB.
    """
    log.info(f"VOLANO: toggle_watchlist s tmdb_id={tmdb_id}")
    if not tmdb_id:
        log.error(f"CHYBA: tmdb_id je NEPLATNÉ.")
        return

    # 1. Zjistíme, jestli už tam je (pouze pro movies)
    current = db.get_by_tmdb_id(tmdb_id, columns=['title_cs', 'ws_watchlist_ts'])
    if not current:
        log.warning(f"CHYBA: Film s ID {tmdb_id} NENÍ v DB media. Přidání selhalo.")
        return
        
    is_in_watchlist = current.get('ws_watchlist_ts') is not None
    name = current.get('title_cs', f"Film s ID {tmdb_id}")
    addon = xbmcaddon.Addon()

    if is_in_watchlist:
        # Odebrat: Nastavíme na NULL
        new_ts = None
        message = "odebrán z"
    else:
        # Přidat: Nastavíme aktuální timestamp
        new_ts = time.time()
        message = "přidán do"

    # 2. Aktualizace databáze
    log.info(f"POKUS O DB UPDATE: {name} ({tmdb_id}). Nastavuji ws_watchlist_ts={new_ts}")
    db.update(tmdb_id, {'ws_watchlist_ts': new_ts}, source='ws_watchlist')
    
    # 3. Zobrazení notifikace uživateli
    xbmcgui.Dialog().notification(
        addon.getAddonInfo('name'),
        f"Film '{name}' {message} 'Sledovat později (Webshare)'.",
        xbmcgui.NOTIFICATION_INFO, 2500
    )
    xbmc.executebuiltin('Container.Refresh')


# ---------------------------------------------------------------------------
# Formátování a čištění textu (sdílené)
# ---------------------------------------------------------------------------

def format_date_cz(date_str: str) -> str:
    """
    Převádí 'YYYY-MM-DD' nebo 'YYYY-MM-DDTHH:MM:SS' na 'dd.mm.yyyy'.
    Při chybě vrátí původní řetězec.
    """
    if not date_str:
        return ""
    try:
        if 'T' in date_str:
            dt = datetime.strptime(date_str.split('T')[0], '%Y-%m-%d')
        else:
            dt = datetime.strptime(date_str, '%Y-%m-%d')
        return dt.strftime('%d.%m.%Y')
    except Exception:
        return date_str

def _light_clean(title: str) -> str:
    """Lehké očištění názvu: ponechá SxxEyy/1x02, odstraní šum (rozlišení/kodek…)."""
    if not title:
        return ""
    # PODSTATNÉ: podtržítka a tečky -> mezery (aby regexy s \s* fungovaly)
    s = title.replace('.', ' ').replace('_', ' ')
    s = re.sub(
        r'(?i)\b(480p|720p|1080p|2160p|4k|webrip|web[\- ]?dl|b[dr]rip|bluray|remux|hdtv|hdr|dv|x264|x265|hevc)\b',
        '',
        s
    )
    s = re.sub(r'\s{2,}', ' ', s).strip(" -.()[]")
    return s

def _normalize_and_slugify(text: str) -> str:
    """Odstraní diakritiku, převede na malá písmena a odstraní nepovolené znaky (jen a-z0-9)."""
    if not text:
        return ''
    # Normalizace UNICODE (odstranění diakritiky)
    normalized = unicodedata.normalize('NFKD', text).encode('ascii', 'ignore').decode('utf-8')
    # Odstranění nepovolených znaků
    slug = re.sub(r'[^a-z0-9]', '', normalized.lower())
    return slug

# --- Pokročilé formátování pro Kalendář ---

MONTHS_CZ_GEN = {
    'Jan': 'ledna', 'Feb': 'února', 'Mar': 'března', 'Apr': 'dubna',
    'May': 'května', 'Jun': 'června', 'Jul': 'července', 'Aug': 'srpna',
    'Sep': 'září', 'Oct': 'října', 'Nov': 'listopadu', 'Dec': 'prosince'
}

def format_full_date_cz(date_str: str) -> str:
    """
    Vrátí datum v plném formátu: 'Čtvrtek, 20. listopadu 2025'.
    Vstup: 'YYYY-MM-DD'
    """
    if not date_str:
        return ""
    try:
        dt = datetime.strptime(date_str, '%Y-%m-%d')
        day_names = ["Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"]
        day_name = day_names[dt.weekday()]
        month_name = MONTHS_CZ_GEN.get(dt.strftime('%b'), dt.strftime('%m'))
        return f"{day_name}, {dt.day}. {month_name} {dt.year}"
    except Exception:
        return date_str

