# -*- coding: utf-8 -*-
#
# resources/resolvers/uktvnow_sp.py
# ──────────────────────────────────────────────────────────────────────
# Resolver per UKTVNow (rocktalk.net) e SPFire (spfire.work)
# integrato nel dispatcher di plugin.video.torproxy
#
# Struttura menu:
#   show_menu()
#     ├─ show_tv_categories()   → show_tv_channels(cat_id)  → play_tv(pk_id)
#     └─ show_sp_categories()   → show_sp_channels(cat_id)  → play_sp(pk_id)
# ──────────────────────────────────────────────────────────────────────

from __future__ import unicode_literals

import sys
import os
import time

# ── Kodi imports ──────────────────────────────────────────────────────
import xbmc
import xbmcgui
import xbmcaddon
import xbmcplugin
from xbmcgui import ListItem
from urllib.parse import urlencode, urlparse
from socket import gethostbyname
from requests.exceptions import RequestException

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

# ── Addon locale ──────────────────────────────────────────────────────
import functions as func
import variables as var

# ─────────────────────────────────────────────────────────────────────
# Helpers interni
# ─────────────────────────────────────────────────────────────────────

_addon = xbmcaddon.Addon()
_PLUGIN_NAME = _addon.getAddonInfo("name")
_USER_DATA_DIR = translatePath(_addon.getAddonInfo("profile"))

if not os.path.exists(_USER_DATA_DIR):
    os.makedirs(_USER_DATA_DIR)


def _log(msg, level=xbmc.LOGDEBUG):
    xbmc.log("[{0}] UKTVSP: {1}".format(_PLUGIN_NAME, msg), level=level)


def _get_handle():
    """Restituisce l'handle corretto dal plugin.video.torproxy."""
    return int(sys.argv[1]) if len(sys.argv) > 1 else -1


def _build_url(mode_id, url="", title="", icon=""):
    """Costruisce un URL plugin:// compatibile con il router di main.py."""
    base = sys.argv[0]
    params = {"mode": "resolver", "link": url, "title2": mode_id}
    if title:
        params["title"] = title
    if icon:
        params["icon"] = icon
    return "{0}?{1}".format(base, urlencode(params))


def _xbmc_curl_encode(stream):
    """Codifica (url, headers_dict) nel formato Kodi url|headers."""
    return "{0}|{1}".format(stream[0], urlencode(stream[1]))


def _resolve_host(stream):
    """DNS-risolve l'host e aggiunge !Host agli headers (per ffmpeg/curl)."""
    url, headers = stream
    parsed = urlparse(url)
    parts = parsed.netloc.split(":")
    try:
        parts[0] = gethostbyname(parts[0])
    except Exception:
        pass
    resolved = parsed._replace(netloc=":".join(parts)).geturl()
    headers["!Host"] = parsed.netloc
    return (resolved, headers)


def _get_stream_plugin():
    val = _addon.getSetting("stream_plugin")
    return val if val else "inputstream.adaptive"


def _make_hls_listitem(title, image, stream):
    """Crea un ListItem HLS secondo il plugin scelto nelle impostazioni."""
    plugin = _get_stream_plugin()
    li = ListItem(title, offscreen=True)

    if plugin == "inputstream.adaptive":
        stream[1]["connection"] = "keep-alive"
        li = ListItem(title, path=_xbmc_curl_encode(stream), offscreen=True)
        li.setContentLookup(False)
        li.setMimeType("application/vnd.apple.mpegurl")
        li.setProperty("inputstream", "inputstream.adaptive")
        li.setProperty("inputstream.adaptive.manifest_type", "hls")
        li.setProperty("inputstream.adaptive.stream_headers", urlencode(stream[1]))
        li.setProperty("inputstream.adaptive.license_key", "|" + urlencode(stream[1]))

    elif plugin == "ffmpegdirect":
        stream = _resolve_host(stream)
        stream[1]["Connection"] = "keep-alive"
        li = ListItem(title, path=_xbmc_curl_encode(stream), offscreen=True)
        li.setContentLookup(False)
        li.setMimeType("application/vnd.apple.mpegurl")
        li.setProperty("inputstream", "inputstream.ffmpegdirect")
        li.setProperty("inputstream.ffmpegdirect.mime_type", "application/vnd.apple.mpegurl")
        li.setProperty("inputstream.ffmpegdirect.is_realtime_stream", "true")

    else:
        # fallback generico / URL diretto
        li = ListItem(title, path=_xbmc_curl_encode(stream), offscreen=True)

    li.setArt({"thumb": image, "icon": image})
    return li


def _pick_stream(links, title):
    """Seleziona lo stream: autoplay se impostato o se c'è un solo link."""
    autoplay = _addon.getSetting("autoplay") == "true"
    if autoplay or len(links) == 1:
        return links[0]
    dialog = xbmcgui.Dialog()
    idx = dialog.select("Scegli stream – {0}".format(title), [l[0] for l in links])
    if idx < 0:
        raise ValueError("Nessuno stream selezionato")
    return links[idx]


# ─────────────────────────────────────────────────────────────────────
# Lazy init delle due istanze TV
# ─────────────────────────────────────────────────────────────────────

_tv_instance = None
_sp_instance = None


def _get_tv():
    global _tv_instance
    if _tv_instance is None:
        # Import da resources/lib/ (cartella lib dentro resources)
        from resources.lib.uktvnow import UKTVNow
        _tv_instance = UKTVNow(_USER_DATA_DIR)
        _maybe_update(_tv_instance, "tv")
    return _tv_instance


def _get_sp():
    global _sp_instance
    if _sp_instance is None:
        # Import da resources/lib/ (cartella lib dentro resources)
        from resources.lib.spfire import UKTVNow as SPFire
        _sp_instance = SPFire(_USER_DATA_DIR)
        _maybe_update(_sp_instance, "sp")
    return _sp_instance


def _maybe_update(instance, prefix):
    """Aggiorna i canali se la cache è scaduta (default 24h)."""
    try:
        data_time  = int(_addon.getSetting("{0}_data_time".format(prefix)) or "0")
        cache_time = int(_addon.getSetting("cache_time") or "24")
        if cache_time == 0:
            cache_time = 24
    except (ValueError, TypeError):
        data_time  = 0
        cache_time = 24

    current = int(time.time())
    if current - data_time > cache_time * 3600:
        try:
            instance.update_channels()
            _addon.setSetting("{0}_data_time".format(prefix), str(current))
            _log("[{0}] canali {1} aggiornati".format(current, prefix))
        except (ValueError, RequestException) as e:
            _log("Aggiornamento {0} fallito: {1}".format(prefix, e))
            if data_time == 0:
                xbmcgui.Dialog().notification(
                    _PLUGIN_NAME,
                    "Errore caricamento dati {0}".format(prefix.upper()),
                    xbmcgui.NOTIFICATION_ERROR,
                    5000
                )


# ─────────────────────────────────────────────────────────────────────
# Funzioni pubbliche — richiamate dal dispatcher
# ─────────────────────────────────────────────────────────────────────

def show_menu():
    """Root: mostra sezioni SPFire (F …) e UKTVNow."""
    handle = _get_handle()
    items = []

    # ── SPFire categories ─────────────────────────────────────────
    try:
        sp = _get_sp()
        for cat in sp.get_categories():
            li = ListItem(" SPFire {0}".format(cat.cat_name), offscreen=True)
            url = _build_url("uktv_sp_channels", str(cat.cat_id), cat.cat_name)
            items.append((url, li, True))
    except Exception as e:
        _log("show_menu SPFire: {0}".format(e), xbmc.LOGWARNING)

    # ── UKTVNow categories ────────────────────────────────────────
    try:
        tv = _get_tv()
        for cat in tv.get_categories():
            li = ListItem(" UKTVNow {0}".format(cat.cat_name), offscreen=True)
            url = _build_url("uktv_tv_channels", str(cat.cat_id), cat.cat_name)
            items.append((url, li, True))
    except Exception as e:
        _log("show_menu UKTVNow: {0}".format(e), xbmc.LOGWARNING)

    if not items:
        xbmcgui.Dialog().ok(_PLUGIN_NAME, "Nessun canale disponibile.\nControlla la connessione e riprova.")

    xbmcplugin.addDirectoryItems(handle, items)
    xbmcplugin.endOfDirectory(handle)


def show_tv_categories():
    """Lista categorie UKTVNow (entry-point alternativo)."""
    handle = _get_handle()
    items = []
    try:
        tv = _get_tv()
        for cat in tv.get_categories():
            li = ListItem(" {0}".format(cat.cat_name), offscreen=True)
            url = _build_url("uktv_tv_channels", str(cat.cat_id), cat.cat_name)
            items.append((url, li, True))
    except Exception as e:
        _log("show_tv_categories: {0}".format(e), xbmc.LOGWARNING)

    xbmcplugin.addDirectoryItems(handle, items)
    xbmcplugin.endOfDirectory(handle)


def show_sp_categories():
    """Lista categorie SPFire (entry-point alternativo)."""
    handle = _get_handle()
    items = []
    try:
        sp = _get_sp()
        for cat in sp.get_categories():
            li = ListItem(" {0}".format(cat.cat_name), offscreen=True)
            url = _build_url("uktv_sp_channels", str(cat.cat_id), cat.cat_name)
            items.append((url, li, True))
    except Exception as e:
        _log("show_sp_categories: {0}".format(e), xbmc.LOGWARNING)

    xbmcplugin.addDirectoryItems(handle, items)
    xbmcplugin.endOfDirectory(handle)


def show_tv_channels(url, title=""):
    """Lista canali UKTVNow per categoria. url = cat_id (stringa)."""
    handle = _get_handle()
    items = []
    try:
        tv = _get_tv()
        for ch in tv.get_channels_by_category(url):
            ch_title = "{0} – {1}".format(ch.country, ch.channel_name.rstrip(".,-"))
            image = tv.image_url(ch.img)
            li = ListItem(ch_title, offscreen=True)
            li.setProperty("IsPlayable", "true")
            li.setArt({"thumb": image, "icon": image})
            li.setInfo("video", {"title": ch_title, "mediatype": "video"})
            play_url = _build_url("uktv_play_tv", str(ch.pk_id), ch_title, image)
            items.append((play_url, li, False))
    except Exception as e:
        _log("show_tv_channels: {0}".format(e), xbmc.LOGWARNING)

    xbmcplugin.addDirectoryItems(handle, items)
    xbmcplugin.setContent(handle, "videos")
    xbmcplugin.endOfDirectory(handle)


def show_sp_channels(url, title=""):
    """Lista canali SPFire per categoria. url = cat_id (stringa)."""
    handle = _get_handle()
    items = []
    try:
        sp = _get_sp()
        for ch in sp.get_channels_by_category(url):
            ch_title = "{0} – {1}".format(ch.country, ch.channel_name.rstrip(".,-"))
            image = sp.image_url(ch.img)
            li = ListItem(ch_title, offscreen=True)
            li.setProperty("IsPlayable", "true")
            li.setArt({"thumb": image, "icon": image})
            li.setInfo("video", {"title": ch_title, "mediatype": "video"})
            play_url = _build_url("uktv_play_sp", str(ch.pk_id), ch_title, image)
            items.append((play_url, li, False))
    except Exception as e:
        _log("show_sp_channels: {0}".format(e), xbmc.LOGWARNING)

    xbmcplugin.addDirectoryItems(handle, items)
    xbmcplugin.setContent(handle, "videos")
    xbmcplugin.endOfDirectory(handle)


def play_tv(url, title=""):
    """Riproduce un canale UKTVNow. url = pk_id (stringa)."""
    handle = _get_handle()
    try:
        tv = _get_tv()
        ch = tv.get_channel_by_id(url)
        ch_title = "{0} – {1}".format(ch.country, ch.channel_name.rstrip(".,-"))
        image = tv.image_url(ch.img)

        links = tv.get_channel_links(url)
        if not links:
            raise ValueError("Nessun link disponibile per questo canale")

        stream = _pick_stream(links, ch_title)

        if "playlist.m3u8" in stream[0] or ".m3u8" in stream[0]:
            li = _make_hls_listitem(ch_title, image, list(stream))
        else:
            li = ListItem(ch_title, path=_xbmc_curl_encode(stream), offscreen=True)
            li.setArt({"thumb": image, "icon": image})

        xbmcplugin.setResolvedUrl(handle, True, li)

    except (ValueError, RequestException) as e:
        _log("play_tv errore: {0}".format(e), xbmc.LOGERROR)
        xbmcgui.Dialog().notification(
            _PLUGIN_NAME, str(e), xbmcgui.NOTIFICATION_ERROR, 5000
        )
        xbmcplugin.setResolvedUrl(handle, False, ListItem())


def play_sp(url, title=""):
    """Riproduce un canale SPFire. url = pk_id (stringa)."""
    handle = _get_handle()
    try:
        sp = _get_sp()
        ch = sp.get_channel_by_id(url)
        ch_title = "{0} – {1}".format(ch.country, ch.channel_name.rstrip(".,-"))
        image = sp.image_url(ch.img)

        links = sp.get_channel_links(url)
        if not links:
            raise ValueError("Nessun link disponibile per questo canale")

        stream = _pick_stream(links, ch_title)

        if "playlist.m3u8" in stream[0] or ".m3u8" in stream[0]:
            li = _make_hls_listitem(ch_title, image, list(stream))
        else:
            li = ListItem(ch_title, path=_xbmc_curl_encode(stream), offscreen=True)
            li.setArt({"thumb": image, "icon": image})

        xbmcplugin.setResolvedUrl(handle, True, li)

    except (ValueError, RequestException) as e:
        _log("play_sp errore: {0}".format(e), xbmc.LOGERROR)
        xbmcgui.Dialog().notification(
            _PLUGIN_NAME, str(e), xbmcgui.NOTIFICATION_ERROR, 5000
        )
        xbmcplugin.setResolvedUrl(handle, False, ListItem())


def force_update():
    """Forza il refresh di entrambi i provider."""
    try:
        from resources.lib.uktvnow import UKTVNow
        from resources.lib.spfire import UKTVNow as SPFire

        tv = UKTVNow(_USER_DATA_DIR)
        tv.update_channels()
        _addon.setSetting("tv_data_time", str(int(time.time())))

        sp = SPFire(_USER_DATA_DIR)
        sp.update_channels()
        _addon.setSetting("sp_data_time", str(int(time.time())))

        xbmcgui.Dialog().notification(
            _PLUGIN_NAME, "Canali aggiornati!", xbmcgui.NOTIFICATION_INFO, 3000
        )
        _log("force_update completato")
    except Exception as e:
        _log("force_update errore: {0}".format(e), xbmc.LOGERROR)
        xbmcgui.Dialog().notification(
            _PLUGIN_NAME, "Aggiornamento fallito: {0}".format(e),
            xbmcgui.NOTIFICATION_ERROR, 5000
        )
