"""
Менеджер лицензий TelePush.
Проверяет ключ через сервер + HWID привязка + offline grace.
"""
import json
import time
import platform
import logging
from pathlib import Path

import requests

from config import TELEPUSH_SERVER_URL, DATA_DIR, TELEPUSH_VERSION as VERSION
from utils.hwid import generate_hwid

logger = logging.getLogger("telepush.license")

_LICENSE_FILE = DATA_DIR / "license.json"
_GRACE_PERIOD = 172800  # 48 часов offline. Раньше было 2 часа — сервер упал
# на 3 часа → у клиента навсегда истекла лицензия хотя ключ валиден ещё 30 дней.
_FIRST_ACTIVATION_TRUST = 86400  # 24 часа доверия при первой активации без сети
# Если сервер недоступен при первой активации — пускаем клиента в работу на сутки,
# в фоне периодически дёргаем сервер. Не подтвердилось за 24 часа — выкидываем.


class LicenseManager:
    def __init__(self):
        self.hwid = generate_hwid()
        self._state = self._load()

    def _load(self) -> dict:
        try:
            if _LICENSE_FILE.exists():
                return json.loads(_LICENSE_FILE.read_text(encoding="utf-8"))
        except Exception:
            pass
        return {}

    def _save(self, data: dict):
        try:
            _LICENSE_FILE.parent.mkdir(parents=True, exist_ok=True)
            _LICENSE_FILE.write_text(json.dumps(data, indent=2), encoding="utf-8")
        except Exception as e:
            logger.warning("Failed to save license: %s", e)

    def activate(self, key: str) -> dict:
        """Активирует ключ на сервере. Возвращает {valid, expires, error}."""
        try:
            resp = requests.post(
                f"{TELEPUSH_SERVER_URL}/api/license/activate",
                json={"key": key, "hwid": self.hwid, "pc_name": platform.node(), "version": VERSION},
                timeout=10,
            )
            data = resp.json()
            if data.get("valid"):
                state = {
                    "key": key,
                    "hwid": self.hwid,
                    "expires": data.get("expires", ""),
                    "last_check": time.time(),
                    "valid": True,
                    "key_type": data.get("key_type", "pro"),
                    "modules": data.get("modules", []),
                    "features": data.get("features", {}),
                }
                self._save(state)
                self._state = state
                return {
                    "valid": True, "expires": data.get("expires", ""),
                    "key_type": data.get("key_type", "pro"),
                    "modules": data.get("modules", []),
                    "features": data.get("features", {}),
                }
            return {"valid": False, "error": data.get("error", "Invalid key")}
        except requests.RequestException as e:
            logger.warning("License activation failed (network): %s — fail-open 24h", e)
            # Fail-open на 24 часа: пускаем клиента в работу даже без сверки.
            # В фоне check() будет периодически пытаться подтвердить ключ. Если
            # за окно доверия не получилось — клиент потеряет доступ.
            state = {
                "key": key,
                "hwid": self.hwid,
                "expires": "",
                "last_check": 0,
                "trust_started_at": time.time(),
                "valid": True,
                "pending_verification": True,
                "key_type": "pro",
                "modules": [],
                "features": {},
            }
            self._save(state)
            self._state = state
            return {
                "valid": True, "expires": "",
                "key_type": "pro", "modules": [], "features": {},
                "pending": True,
                "warning": (
                    "Сервер недоступен — пускаем в работу на 24 часа. "
                    "В фоне будем пытаться подтвердить ключ. "
                    "Если за это время сеть до сервера не появится — потребуется повторная активация."
                ),
            }

    def check(self, key: str = None) -> dict:
        """Проверяет лицензию. Поддерживает offline grace period."""
        key = key or self._state.get("key", "")
        if not key:
            return {"valid": False, "error": "No license key"}

        try:
            resp = requests.post(
                f"{TELEPUSH_SERVER_URL}/api/license/check",
                json={"key": key, "hwid": self.hwid, "pc_name": platform.node(), "version": VERSION},
                timeout=10,
            )
            data = resp.json()
            if data.get("valid"):
                self._state["last_check"] = time.time()
                self._state["valid"] = True
                self._state["key_type"] = data.get("key_type", "pro")
                self._state["modules"] = data.get("modules", [])
                self._state["features"] = data.get("features", {})
                self._state["expires"] = data.get("expires", "") or self._state.get("expires", "")
                # Снимаем pending после первой удачной сверки — теперь обычный grace
                if self._state.get("pending_verification"):
                    self._state["pending_verification"] = False
                    self._state.pop("trust_started_at", None)
                    logger.info("License: pending verification confirmed by server")
                self._save(self._state)
                return {
                    "valid": True, "expires": data.get("expires", ""),
                    "key_type": data.get("key_type", "pro"),
                    "modules": data.get("modules", []),
                    "features": data.get("features", {}),
                }
            # Сервер сказал invalid
            self._state["valid"] = False
            self._save(self._state)
            return {"valid": False, "error": data.get("error", "License invalid")}
        except requests.RequestException:
            # Offline — два режима:
            # 1) Стандартный grace 48ч если ключ уже был подтверждён хоть раз.
            # 2) Trust-window 24ч если активация прошла в режиме fail-open
            #    (ключ ни разу не сверялся успешно с сервером).
            last = self._state.get("last_check", 0)
            if self._state.get("valid") and last > 0 and (time.time() - last) < _GRACE_PERIOD:
                logger.info("License check: offline grace period active")
                return {"valid": True, "expires": self._state.get("expires", ""), "offline": True}
            if self._state.get("pending_verification"):
                trust_start = self._state.get("trust_started_at", 0)
                if trust_start and (time.time() - trust_start) < _FIRST_ACTIVATION_TRUST:
                    logger.info("License check: first-activation trust window active")
                    return {"valid": True, "expires": "", "offline": True, "pending": True}
            host = TELEPUSH_SERVER_URL.split("//", 1)[-1].rstrip("/")
            return {"valid": False, "error": (
                f"Сервер {host} не отвечает. "
                "Проверьте интернет/firewall/прокси на этом ПК."
            )}

    def is_valid(self) -> bool:
        """Быстрая проверка без сети."""
        return bool(self._state.get("valid")) and bool(self._state.get("key"))

    def get_key(self) -> str:
        return self._state.get("key", "")

    def get_uid(self) -> int:
        """Детерминированный UID из HWID."""
        return int(self.hwid[:8], 16) % 10**9
