# resources/lib/webshare_auth.py
# -*- coding: utf-8 -*-

import hashlib
import io
import uuid
from xml.etree import ElementTree as ET
import requests
import xbmc
import xbmcgui
import xbmcaddon
from resources.lib.utils.log_utils import get_logger

log = get_logger()

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

try:
    from md5crypt import md5crypt
except Exception:
    md5crypt = None

# Konstanty (ponechány stejné jako v původním kořenovém bridge)
BASE = 'https://webshare.cz'
API_BASE = BASE + '/api/'
UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
      "AppleWebKit/537.36 (KHTML, like Gecko) "
      "Chrome/81.0.4044.138 Safari/537.36")
HEADERS = {'User-Agent': UA, 'Referer': BASE}
REALM = ':Webshare:'


def _popinfo(message, heading=None, icon=xbmcgui.NOTIFICATION_INFO, time=3000, sound=False):
    """Malý helper pro nenápadné toasty (aby modul fungoval i „mimo“ hlavní soubor)."""
    heading = heading or xbmcaddon.Addon().getAddonInfo('name')
    xbmcgui.Dialog().notification(heading, message, icon, time, sound=sound)


class WebshareClient(object):
    """
    Lehký klient pro autentizaci a volání Webshare API.
    - Uchovává token v Kodi Settings (stejné klíče jako dosud).
    - Odděluje Webshare logiku od kořenového bridge: poskytuje kompatibilní metody.
    """

    def __init__(self, addon_id='plugin.video.mmirousek_v3'):
        self.addon_id = addon_id
        self.addon = xbmcaddon.Addon(addon_id)
        self.session = requests.Session()
        self.session.headers.update(HEADERS)
        self._ensure_uuid()
        self._last_error = ""   # poslední chybová zpráva z API (např. z file_link)

    # ---- Pomocné metody -----------------------------------------------------

    def _ensure_uuid(self):
        duuid = self.addon.getSetting('duuid')
        if not duuid:
            duuid = str(uuid.uuid4())
            self.addon.setSetting('duuid', duuid)
        self.duuid = duuid

    def _token_get(self):
        return self.addon.getSetting('token') or ''

    def _token_set(self, token):
        self.addon.setSetting('token', token or '')

    def _xml_ok(self, xml_root):
        status_el = xml_root.find('status')
        return (status_el is not None) and (status_el.text == 'OK')

    # ---- Veřejné API (stejné názvy jako v sm3_entry.py) -------------------------

    def api(self, fnct, data):
        """POST na /api/<fnct>/; vrací `requests.Response` (stejně jako dřív)."""
        return self.session.post(API_BASE + fnct + "/", data=data)

    def login(self, interactive=False):
        """
        Přihlášení – uloží token do settings a vrátí jej (nebo None).

        interactive=False  → tichý režim (neotevírá Settings, pouze krátký toast)
        interactive=True   → při problému/absenci údajů otevře Nastavení
        """
        username = self.addon.getSetting('wsuser')
        password = self.addon.getSetting('wspass')

        if not username or not password:
            _popinfo('Pro použití tohoto pluginu nutné zadat v nastaveních konto pro Webshare.', sound=False)
            if interactive:
                self.addon.openSettings()
            return None

        # 1) Získání soli
        resp = self.api('salt', {'username_or_email': username})
        try:
            xml = ET.fromstring(resp.content)
        except Exception as e:
            log.error(f"ERROR salt parse: {e}")
            _popinfo('Neplatné přihlašovací údaje!',
                     icon=xbmcgui.NOTIFICATION_ERROR, sound=False)
            return None

        if not self._xml_ok(xml):
            _popinfo('Neplatné přihlašovací údaje!',
                     icon=xbmcgui.NOTIFICATION_ERROR, sound=False)
            if interactive:
                self.addon.openSettings()
            return None

        salt = xml.find('salt').text if xml.find('salt') is not None else ''
        if not md5crypt:
            log.error("md5crypt modul chybí – nelze vytvořit digest")
            _popinfo('Neplatné přihlašovací údaje!',
                     icon=xbmcgui.NOTIFICATION_ERROR, sound=False)
            return None

        # 2) Vytvoření digestu (stejně jako dřív)
        try:
            encrypted_pass = hashlib.sha1(md5crypt(password.encode('utf-8'),
                                                   salt.encode('utf-8'))).hexdigest()
            pass_digest = hashlib.md5(
                username.encode('utf-8') +
                REALM.encode('utf-8') +
                encrypted_pass.encode('utf-8')
            ).hexdigest()
        except TypeError:
            encrypted_pass = hashlib.sha1(
                md5crypt(password.encode('utf-8'), salt.encode('utf-8')).encode('utf-8')
            ).hexdigest()
            pass_digest = hashlib.md5(
                username.encode('utf-8') +
                REALM.encode('utf-8') +
                encrypted_pass.encode('utf-8')
            ).hexdigest()

        # 3) Login
        data = {
            'username_or_email': username,
            'password': encrypted_pass,
            'digest': pass_digest,
            'keep_logged_in': 1
        }
        resp = self.api('login', data)
        try:
            xml = ET.fromstring(resp.content)
        except Exception as e:
            log.error(f"ERROR login parse: {e}")
            _popinfo('Neplatné přihlašovací údaje!',
                     icon=xbmcgui.NOTIFICATION_ERROR, sound=False)
            return None

        if not self._xml_ok(xml):
            _popinfo('Neplatné přihlašovací údaje!',
                     icon=xbmcgui.NOTIFICATION_ERROR, sound=False)
            if interactive:
                self.addon.openSettings()
            return None

        token = xml.find('token').text if xml.find('token') is not None else ''
        self._token_set(token)

        try:
            self.refresh_vip_settings(show_toast=False)
        except Exception:
            pass

        return token

    def revalidate(self):
        """Zajistí platný token a vrátí jej (stejně jako dřív)."""
        token = self._token_get()
        if not token:
            token = self.login(interactive=False)
        if not token:
            return None

        resp = self.api('user_data', {'wst': token})
        try:
            xml = ET.fromstring(resp.content)
        except Exception as e:
            log.error(f"ERROR user_data parse: {e}")
            return None

        if self._xml_ok(xml):
            vip = xml.find('vip').text if xml.find('vip') is not None else '0'
            if vip != '1':
                _popinfo('Nemáte platné VIP.',
                         icon=xbmcgui.NOTIFICATION_WARNING)
            try:
                self.refresh_vip_settings(show_toast=False)
            except Exception:
                pass
            return token

        token = self.login(interactive=False)
        if token:
            return self.revalidate()
        return None

    def getlink(self, ident, dtype='video_stream'):
        """Vrátí stream/download link nebo None (a uloží poslední chybu)."""
        self._last_error = ""
        token = self._token_get() or self.revalidate()
        if not token:
            self._last_error = "NO_TOKEN"
            return None

        data = {
            'ident': ident,
            'wst': token,
            'download_type': dtype,
            'device_uuid': self.duuid
        }
        resp = self.api('file_link', data)
        try:
            xml = ET.fromstring(resp.content)
        except Exception as e:
            log.error(f"ERROR file_link parse: {e}")
            self._last_error = "PARSE_ERROR"
            _popinfo('Vznikla chyba při komunikaci s Webshare API.',
                     icon=xbmcgui.NOTIFICATION_WARNING)
            return None

        if self._xml_ok(xml):
            link_el = xml.find('link')
            return link_el.text if link_el is not None else None

        msg = ""
        for tag in ("message", "error", "detail", "reason"):
            el = xml.find(tag)
            if el is not None:
                text = (el.text or "").strip()
                if text:
                    msg = text
                    break
        self._last_error = msg or "UNKNOWN_ERROR"

        _popinfo('Vznikla chyba při komunikaci s Webshare API.',
                 icon=xbmcgui.NOTIFICATION_WARNING)
        return None

    def get_last_error(self):
        return self._last_error or ""

    def _set_setting_safe(self, key, val):
        try:
            self.addon.setSetting(key, str(val if val is not None else '—'))
        except Exception as e:
            log.warning(f"setSetting {key} failed: {e}")

    def fetch_user_data(self):
        token = self._token_get() or self.revalidate()
        if not token:
            return None
        resp = self.api('user_data', {'wst': token})
        try:
            return ET.fromstring(resp.content)
        except Exception as e:
            log.error(f"user_data parse failed: {e}")
            return None

    def get_vip_info(self):
        root = self.fetch_user_data()
        if root is None:
            return 0, ''
        status = root.findtext('status', '') or ''
        if status != 'OK':
            return 0, ''
        raw_days = root.findtext('vip_days', '') or ''
        vip_until = root.findtext('vip_until', '') or ''
        try:
            vip_days = int(raw_days)
        except Exception:
            vip_days = 0
        return vip_days, vip_until

    def refresh_vip_settings(self, show_toast=True):
        try:
            win = xbmcgui.Window(10000)
            already = win.getProperty('mm_ws_vip_toast_shown') == '1'
            if already:
                show_toast = False
        except Exception:
            pass

        vip_days, vip_until = self.get_vip_info()
        self._set_setting_safe('ws_vip_days', vip_days if vip_days is not None else '—')
        self._set_setting_safe('ws_vip_until', vip_until or '—')

        if show_toast:
            xbmcgui.Dialog().notification(
                self.addon.getAddonInfo('name'),
                f"VIP: zbývá {vip_days} dní • do {vip_until or '—'}",
                xbmcgui.NOTIFICATION_INFO,
                3000
            )
        try:
            win.setProperty('mm_ws_vip_toast_shown', '1')
        except Exception:
            pass
