# -*- coding: utf-8 -*-
import sys
import xbmc
import xbmcgui
import xbmcplugin
import xbmcaddon
import requests
import re
import json
import time
import base64
import random
from urllib.parse import quote_plus, unquote, parse_qsl

ADDON = xbmcaddon.Addon()
HANDLE = int(sys.argv[1])

portal_setting = ADDON.getSetting("portal")
mac_setting = ADDON.getSetting("mac")

if portal_setting and mac_setting:
    PORTAL, MAC = portal_setting, mac_setting
else:
    PORTAL, MAC = random.choice([(k, random.choice(v)) for k, v in json.loads(base64.b64decode(" ")).items()])

TIMEOUT = 15

UA = "Mozilla/5.0 (QtEmbedded; Linux; MAG200) stbapp ver: 2 rev: 250"

def log(msg):
    xbmc.log(f"[ManeTv] {msg}", xbmc.LOGINFO)

class StalkerClient:
    def __init__(self):
        self.session = requests.Session()
        self.session.verify = False
        self.session.headers.update({"User-Agent": UA})
        self.session.cookies.set("mac", MAC)
        self.portal = PORTAL.rstrip("/")
        self.token = None
        self.token_expiry = 0

    def handshake(self):
        if self.token and time.time() < self.token_expiry:
            return self.token
        self.session.cookies.clear()
        self.session.cookies.set("mac", MAC)
        r = self.session.get(
            f"{self.portal}/portal.php?type=stb&action=handshake&JsHttpRequest=1-xml",
            timeout=TIMEOUT
        )
        m = re.search(r'"token"\s*:\s*"([^"]+)"', r.text)
        if not m:
            return None
        self.token = m.group(1)
        self.token_expiry = time.time() + 3500
        return self.token

    def api(self, params):
        if not self.handshake():
            return []
        params["token"] = self.token
        params["JsHttpRequest"] = "1-xml"
        r = self.session.get(
            f"{self.portal}/server/load.php",
            params=params,
            timeout=TIMEOUT
        )
        try:
            data = r.json().get("js")
            if isinstance(data, dict) and "data" in data:
                return data["data"]
            if isinstance(data, list):
                return data
        except:
            pass
        return []
    
    def api_film(self, params):
        if not self.handshake():
            return []
        params["token"] = self.token
        params["JsHttpRequest"] = "1-xml"
        r = self.session.get(
            f"{self.portal}/server/load.php",
            params=params,
            timeout=TIMEOUT
        )
        log(r.json())
        try: 
            data = r.json().get("js")
            if isinstance(data, dict) and "cmd" in data:
                return data["cmd"]
        except:
            pass
        return []

    def get_genres(self):
        return self.api({"type": "itv", "action": "get_genres"}) or []

    def get_all_channels(self):
        channels = self.api({"type": "itv", "action": "get_all_channels"}) or []
        out = []
        for ch in channels:
            cmd = ch.get("cmd", "")
            if cmd.startswith("ffmpeg "):
                cmd = cmd[7:]
            out.append({
                "name": ch.get("name", ""),
                "cmd": cmd,
                "logo": ch.get("logo", ""),
                "genre": str(ch.get("tv_genre_id", ""))
            })
        return out

client = StalkerClient()

def add_dir(label, action, **params):
    url = f"{sys.argv[0]}?action={action}"
    for k, v in params.items():
        url += f"&{k}={quote_plus(str(v))}"
    xbmcplugin.addDirectoryItem(HANDLE, url, xbmcgui.ListItem(label), True)

def main_menu():
    add_dir("📺 Live TV", "live_cats")
    add_dir("🎬 Movies", "vod_cats")
    xbmcplugin.endOfDirectory(HANDLE)

def live_cats():
    add_dir("🔍 Search Channels", "search_live")
    add_dir("⭐ All Channels", "live_list")
    for g in client.get_genres():
        add_dir(g.get("title", "Unknown"), "live_list", genre=g.get("id"))
    xbmcplugin.endOfDirectory(HANDLE)

def live_list(genre=""):
    for ch in client.get_all_channels():
        if not genre or ch["genre"] == genre:
            add_play(ch["name"], ch["cmd"], "itv", ch["logo"])
    xbmcplugin.endOfDirectory(HANDLE)

def search_live():
    kb = xbmc.Keyboard("", "Search Channels")
    kb.doModal()
    if not kb.isConfirmed():
        return
    q = kb.getText().lower()
    for ch in client.get_all_channels():
        if q in ch["name"].lower():
            add_play(ch["name"], ch["cmd"], "itv", ch["logo"])
    xbmcplugin.endOfDirectory(HANDLE)

def vod_cats():
    #add_dir("🔍 Search Movies", "search_vod") takes too long to load and the token has probably expired by the time you find a result
    cats = client.api({"type": "vod", "action": "get_categories"}) or []
    for c in cats:
        add_dir(c.get("title", "Unknown"), "vod_list", genre=c.get("id"))
    xbmcplugin.endOfDirectory(HANDLE)

def add_play(label, cmd, ctype="itv", logo=""):
    li = xbmcgui.ListItem(label)
    li.setProperty("IsPlayable", "true")

    if logo:
        li.setArt({"thumb": logo, "icon": logo})

    url = (
        f"{sys.argv[0]}?"
        f"action=play"
        f"&type={ctype}"
        f"&cmd={quote_plus(str(cmd))}"
    )

    xbmcplugin.addDirectoryItem(HANDLE, url, li, False)

def vod_list(genre):
    p = 1
    while True:
        data = client.api({
            "type": "vod",
            "action": "get_ordered_list",
            "genre": genre,
            "p": p
        })

        items = data if isinstance(data, list) else data.get("data", [])
        if not items:
            break

        for v in items:
            vod_cmd = v.get("cmd")  
            if not vod_cmd:
                continue
            add_play(
                v.get("name", "Unknown"),
                vod_cmd,       
                ctype="vod"
            )

        if isinstance(data, dict) and len(items) < data.get("max_page_items", 0):
            break
        p += 1

    xbmcplugin.endOfDirectory(HANDLE)

def search_vod():
    kb = xbmc.Keyboard("", "Search Movies")
    kb.doModal()
    if not kb.isConfirmed():
        return

    q = kb.getText().lower()
    while True:
        data = client.api({
            "type": "vod",
            "action": "get_ordered_list"
        })
        if not data:
            break
        # Extract list of movies
        items = data
        log(items)
        if not items:
            break

        for v in items:
            if q in v.get("name", "").lower():
                add_play(v.get("name", "Unknown"), v.get("cmd") , "vod")

        # Stop if we got fewer items than the page size
        if isinstance(data, dict) and len(items) < data.get("max_page_items", 0):
            break


    xbmcplugin.endOfDirectory(HANDLE)


def play_stream(ctype, raw_cmd):
    try:
        cmd = unquote(raw_cmd).strip()

        if ctype == "itv":
            stream_url = cmd

        else:
            log("[ER TEST] resolving vod via create_link")
            log(cmd)

            # Decode Base64 cmd from vod_list
            try:
                decoded = base64.b64decode(cmd).decode("utf-8")
                cmd_dict = json.loads(decoded)
            except Exception as e:
                log(f"[ER TEST] failed to decode cmd: {e}")
                xbmcgui.Dialog().notification(
                    "Error",
                    "Failed to decode movie cmd",
                    xbmcgui.NOTIFICATION_ERROR
                )
                return

            stream_id = cmd_dict.get("stream_id")
            containers = cmd_dict.get("target_container", ["mp4"])
            ext = containers[0] if containers else "mp4"

            data = client.api_film({
                "type": "vod",
                "action": "create_link",
                "cmd": cmd
            })
            if not data:
                xbmcgui.Dialog().notification(
                    "Error",
                    "Unable to resolve movie stream",
                    xbmcgui.NOTIFICATION_ERROR
                )
                return

            stream_url = data.replace("stream=.", f"stream={stream_id}.{ext}") 

            if stream_url.startswith("ffmpeg "):
                stream_url = stream_url[7:].strip()

        li = xbmcgui.ListItem(path=stream_url)
        li.setProperty("IsPlayable", "true")
        li.setContentLookup(False)

        xbmcplugin.setResolvedUrl(HANDLE, True, li)

    except Exception as e:
        log(f"[ER TEST] PLAY ERROR: {e}")

params = dict(parse_qsl(sys.argv[2][1:])) if len(sys.argv) > 2 else {}
action = params.get("action", "")

if action == "live_cats":
    live_cats()
elif action == "live_list":
    live_list(params.get("genre", ""))
elif action == "search_live":
    search_live()
elif action == "vod_cats":
    vod_cats()
elif action == "vod_list":
    vod_list(params.get("genre"))
elif action == "search_vod":
    search_vod()
elif action == "play":
    play_stream(params.get("type", "itv"), params.get("cmd", ""))
else:
    main_menu()
