#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
tor_mac_check.py  –  parte di plugin.video.torproxy
"""

import re
import json
import datetime
import logging
from contextlib import nullcontext
from tor_manager import TorManager, get_tor_manager, tor_enabled

log = logging.getLogger("tor_mac_check")

def _get_addon_path():
    """Percorso di plugin.video.torproxy, affidabile anche da import esterni."""
    try:
        import xbmcaddon
        import xbmcvfs
        return xbmcvfs.translatePath(
            xbmcaddon.Addon('plugin.video.torproxy').getAddonInfo('path')
        )
    except Exception:
        import os as _os
        return _os.path.dirname(_os.path.abspath(__file__))


# Singleton condiviso — evita terza istanza separata di TorManager.
# Se variables.py e' stato importato prima, get_tor_manager() restituisce
# la stessa istanza gia' inizializzata (Tor non viene riavviato).
_tor = get_tor_manager(
    use_tor=True,
    fallback=True,
    auto_start=True,
    addon_path=_get_addon_path(),
)


class TorPortalApi:

    def __init__(self, url):
        match = re.compile(
            r'(.*?)\?(.*?)($|(&.*?$))', re.MULTILINE
        ).findall(url)[0]
        self.url   = match[0]
        self.mac   = match[1]
        try:
            self.params = re.compile(r'([^&?]*?)=([^&?]*)').findall(match[2])
        except Exception:
            self.params = []
        self.api_url = self.url + "/portal.php?"
        self.token   = ""

    def _headers(self):
        from urllib.parse import quote as quoter
        ua = (
            'Mozilla/5.0 (QtEmbedded; U; Linux; C) AppleWebKit/533.3 '
            '(KHTML, like Gecko) MAG200 stbapp ver: 2 rev: 250 Safari/533.3'
        )
        h = {
            'User-Agent'      : ua,
            'X-User-Agent'    : 'Model: MAG250; Link: WiFi',
            'Connection'      : 'keep-Alive',
            'Cookie'          : 'mac=' + quoter(self.mac) + '; stb_lang=en; timezone=Europe%2Amsterdam;',
            'Pragma'          : 'no-cache',
            'Accept'          : '*/*',
            'Content-Type'    : 'application/x-www-form-urlencoded',
            'Accept-Encoding' : 'gzip',
        }
        if self.token:
            h['Authorization'] = 'Bearer ' + self.token
        return h

    def _do_request(self, query, is_get=False):
        from urllib.parse import urlparse, parse_qs
        request_url = self.api_url + query + "&JsHttpRequest=1-xml"
        parsed      = urlparse(request_url)
        payload     = parse_qs(parsed.query)
        headers     = self._headers()
        log.debug("_do_request %s %s", "GET" if is_get else "POST", self.api_url)

        # Tentativo 1: via TorManager (usa Tor se disponibile)
        try:
            with tor_enabled():
                if is_get:
                    resp = _tor.session.get(
                        self.api_url, headers=headers, params=payload, timeout=15
                    )
                else:
                    resp = _tor.session.post(
                        self.api_url, headers=headers, data=payload, timeout=15
                    )
            log.debug("_do_request risposta HTTP %s", resp.status_code)
            if resp.status_code <= 399:
                return resp.json().get("js")
            log.warning("_do_request HTTP %s", resp.status_code)
        except Exception as exc:
            log.warning("_do_request via Tor fallito: %s", exc)

        # Tentativo 2: connessione diretta senza proxy Tor
        # Usa _tor.session (senza proxy se Tor non disponibile) invece di
        # requests.get() globale, per evitare interferenze con il socket.
        if _tor.fallback:
            try:
                log.info("_do_request FALLBACK diretto (session)")
                if is_get:
                    resp = _tor.session.get(
                        self.api_url, headers=headers, params=payload, timeout=15
                    )
                else:
                    resp = _tor.session.post(
                        self.api_url, headers=headers, data=payload, timeout=15
                    )
                if resp.status_code <= 399:
                    return resp.json().get("js")
            except Exception as exc2:
                log.warning("_do_request FALLBACK diretto fallito: %s", exc2)

        # Tentativo 3: bypass DoH (Android senza Tor)
        try:
            from bypass import get_with_bypass
            log.info("_do_request bypass DoH per: %s", self.api_url)
            # Ricostruiamo l'URL con i parametri per il bypass
            import urllib.parse as _up
            full_url = self.api_url + query + "&JsHttpRequest=1-xml"
            result = get_with_bypass(full_url, headers=headers, timeout=15)
            if result:
                import json as _json
                try:
                    jres = _json.loads(result)
                    return jres.get("js")
                except Exception:
                    log.warning("_do_request bypass: risposta non JSON")
        except Exception as exc3:
            log.error("_do_request bypass fallito: %s", exc3)

        return None

    def get_token(self):
        res = self._do_request("type=stb&action=handshake")
        if res:
            self.token = res.get("token", "")
            self._get_profile()

    def _get_profile(self):
        import time
        ts = str(time.time())
        p = (
            'type=stb&action=get_profile&hd=1'
            '&ver=ImageDescription: 0.2.18-r23-254; ImageDate: Wed Oct 31 15:22:54 EEST 2018; '
            'PORTAL version: 5.5.0; API Version: JS API version: 343; STB API version: 146; '
            'Player Engine version: 0x58c'
            '&num_banks=2&sn=17F88C9910EF5&client_type=STB&image_version=218&video_out=hdmi'
            '&device_id=F48C7788EF17D24F661C5A1782DF0D2237D545BE12A5A4B4325D89A52A7DF186'
            '&device_id2=F48C7788EF17D24F661C5A1782DF0D2237D545BE12A5A4B4325D89A52A7DF186'
            '&signature=845519FCE3386C1847AD3469AAD6D2773080C6F94CB59CD0A9E82605FAEDE02F'
            '&auth_second_step=1&hw_version=2.6-IB-00&not_valid_token=0'
            '&metrics={"mac":"' + self.mac + '",'
            '"sn":"17F88C9910EF5","type":"STB","model":"MAG254",'
            '"uid":"F48C7788EF17D24F661C5A1782DF0D2237D545BE12A5A4B4325D89A52A7DF186",'
            '"random":""}'
            '&hw_version_2=aff4d6ab1ab4e0660f09f89809c6e9782fa43263'
            '&timestamp=' + ts + '&api_signature=262'
        )
        self._do_request(p)

    def get_itv_genres(self):
        return self._get_categories("live")

    def get_vod_genres(self):
        return self._get_categories("vod")

    def _get_categories(self, ltype="live"):
        self.get_token()
        if not self.token:
            log.warning("_get_categories: token vuoto, portale non raggiungibile")
            return []
        url = "type=itv&action=get_genres" if ltype == "live" else "type=vod&action=get_categories"
        res = self._do_request(url, True)
        if not res:
            return []
        ret = []
        for gen in res:
            title = gen["title"].encode('utf-8', errors='ignore').decode()
            if title.lower() == "all":
                continue
            ret.append((gen["id"], title, self.url + "?" + self.mac))
        return ret

    def get_itv_list(self, id_genre):
        return self._get_ordered_list(id_genre, "live")

    def get_vod_list(self, id_categ):
        return self._get_ordered_list(id_categ, "vod")

    def _get_ordered_list(self, id_genre, ltype="live"):
        import math
        self.get_token()
        if not self.token:
            return []
        if ltype == "live":
            base = "type=itv&action=get_ordered_list&genre=" + str(id_genre)
        else:
            base = "type=vod&action=get_ordered_list&genre=" + str(id_genre)
        base += "&force_ch_link_check=&fav=0&sortby=number&hd=0"
        ret       = []
        tot_pages = 0
        page      = 1
        while True:
            res = self._do_request(base + "&p=" + str(page), True)
            if res and "data" in res:
                for ch in res["data"]:
                    ret.append((ch["name"], ch["cmd"]))
            if tot_pages == 0 and res:
                try:
                    tot_pages = math.ceil(
                        int(res.get("total_items", 1)) / int(res.get("max_page_items", 1))
                    )
                except Exception:
                    tot_pages = 1
            page += 1
            if page > max(tot_pages, 1):
                break
        return ret

    def get_link(self, cmd, ltype="itv"):
        self.get_token()
        if not self.token:
            return cmd
        url = (
            "type=" + ltype + "&action=create_link&cmd=" + cmd
            + "&series=0&forced_storage=false&disable_ad=false"
            + "&download=false&force_ch_link_check=false"
        )
        res = self._do_request(url, True)
        if res:
            if res["id"].isdigit():
                link = res["cmd"]
            else:
                try:
                    strm_id = re.compile(
                        r".*?/([\d]+(?:\.ts|$))"
                    ).findall(res["id"])[0]
                    base = re.compile(
                        r"(http.*?://.*?:[\d]+(?:/live/|/).*?/.*?/).*?(\?.*?)$"
                    ).findall(res["cmd"])[0]
                    link = base[0] + strm_id + base[1]
                except Exception:
                    link = cmd
        else:
            link = cmd
        try:
            link = link.split(" ")[1]
        except Exception:
            pass
        params = ""
        if self.params:
            for par in self.params:
                params += "=".join(par) + "&"
        params = params.strip("&")
        if "User-Agent" not in params:
            params += "!User-Agent=Lavf53.32.100"
        if "Icy-MetaData" not in params:
            params += "&Icy-MetaData=1"
        return link + "|" + params


def panel_list_tor(url):
    try:
        url = url.split(";")[0]
        base_url = username = password = None
        try:
            base_url = re.compile(r'(http.*?://.*?/)').findall(url)[0]
        except Exception:
            pass
        try:
            username = re.compile(r'username=(.*?)(?:&|$)').findall(url)[0]
        except Exception:
            pass
        try:
            password = re.compile(r'password=(.*?)(?:&|$)').findall(url)[0]
        except Exception:
            pass
        try:
            l_type = re.compile(r'type=(.*?)(?:&|$)').findall(url)[0]
        except Exception:
            l_type = None
        if not l_type or (l_type != "m3u" and l_type != "m3u8"):
            text = _tor.get(url, timeout=15)
            if not text:
                # Fallback bypass DoH per Android
                try:
                    from bypass import get_with_bypass
                    text = get_with_bypass(url, timeout=15)
                except Exception:
                    pass
            if text:
                expr = r'(http.*?//(.*?/).*?)/([\d]+(?:\.ts|\.m3u8)?)\s'
                m = re.compile(expr, re.MULTILINE).findall(text)
                if m:
                    match_url = m[0][0].replace("/live/", "/")
                    expr2 = r'(http.*?://.*?:[\d]+/)(.*?)/(.*?)$'
                    m2 = re.compile(expr2, re.IGNORECASE).findall(match_url)
                    if m2:
                        base_url = m2[0][0]
                        username = m2[0][1]
                        password = m2[0][2]
        if base_url and username and password:
            panel_url = (
                base_url + "player_api.php?username="
                + username + "&password=" + password + "&"
            )
            text = _tor.get(panel_url, timeout=15)
            if not text:
                try:
                    from bypass import get_with_bypass
                    text = get_with_bypass(panel_url, timeout=15)
                except Exception:
                    pass
            if not text:
                return None
            data = json.loads(text)
            info = data["user_info"]
            try:
                expires = datetime.datetime.fromtimestamp(
                    float(info["exp_date"])
                ).strftime("%d/%m/%Y")
            except Exception:
                expires = "-"
            return [
                str(info["status"]),
                str(info["active_cons"]),
                str(info["max_connections"]),
                str(info["auth"]),
                expires,
            ]
    except Exception as exc:
        log.error("panel_list_tor fallito: %s", exc)
        return None


def mac_list_check_tor(url):
    try:
        portal = TorPortalApi(url)
        link   = portal.get_link("ffmpeg%20http://localhost/ch/1823_&series=")
        log.debug("mac_list_check_tor get_link: %s", link)
        try:
            link = link.split(" ")[1]
        except Exception:
            pass
        expr    = r'(http.*?://.*?:[\d]+/)(.*?)/(.*?)/.*?$'
        matches = re.compile(expr, re.IGNORECASE).findall(link)
        if not matches:
            log.warning("mac_list_check_tor: credenziali non trovate in: %s", link)
            return None
        base_url = matches[0][0]
        username = matches[0][1]
        password = matches[0][2]
        check_url = (
            base_url + "get.php?username=" + username
            + "&password=" + password + "&type=m3u"
        )
        return panel_list_tor(check_url)
    except Exception as exc:
        log.error("mac_list_check_tor fallito: %s", exc)
        return None
