"""
Busca automatica de renovacao de licenca. Periodicamente (e a cada carregamento
da tela de ativacao/bloqueio), pergunta ao servidor se ha uma chave nova
publicada pro codigo deste cliente e adota sozinho se encontrar.

IMPORTANT: ajuste LICENSE_SERVER_URL para o endereço real onde
licencas_server/ foi publicado (ex: https://licencas.compucellinformatica.com.br).
"""
import os

import requests

from . import security

LICENSE_SERVER_URL = os.getenv("LICENSE_SERVER_URL", "https://licencas.compucellinformatica.com.br")
PRODUTO = "frota-trucks"
REQUEST_TIMEOUT_SECONDS = 6


def fetch_published_key(machine_id: str) -> str | None:
    """Retorna a chave publicada no servidor pro codigo, ou None (sem internet/nao publicada)."""
    try:
        resp = requests.get(
            f"{LICENSE_SERVER_URL}/api/chave/{machine_id}",
            params={"produto": PRODUTO},
            timeout=REQUEST_TIMEOUT_SECONDS,
        )
        if resp.status_code == 404:
            return None
        resp.raise_for_status()
        return resp.json().get("chave")
    except Exception:
        return None


def try_adopt_new_key(machine_id: str, nome_empresa: str) -> bool:
    """
    Busca a chave publicada pro codigo; se for diferente/mais nova que a atual
    e validar certinho pra esse codigo, adota e salva. Retorna True se a
    licenca ativa (apos a chamada) e valida.
    """
    chave_remota = fetch_published_key(machine_id)
    if chave_remota:
        atual = security.load_active_license()
        ja_tem_essa = atual and _chave_atual_local() == chave_remota
        if not ja_tem_essa:
            ok, info = security.validate_license_key(machine_id, chave_remota)
            if ok:
                security.save_license(chave_remota, nome_empresa, info)

    return security.load_active_license() is not None


def _chave_atual_local() -> str | None:
    import json
    if not security.LICENSE_FILE.exists():
        return None
    try:
        return json.loads(security.LICENSE_FILE.read_text(encoding="utf-8")).get("license_key")
    except Exception:
        return None


def refresh_from_server() -> bool:
    """
    Usado pelo scheduler em background e pelo botao 'verificar agora': tenta
    renovar usando o codigo/empresa ja conhecidos localmente (de uma ativacao
    anterior, mesmo que a chave atual ja tenha vencido).
    """
    dados = known_activation_data()
    if not dados:
        return security.load_active_license() is not None
    return try_adopt_new_key(dados["machine_id"], dados["company"])


def known_activation_data() -> dict | None:
    """Le codigo/empresa do license.json mesmo que a chave nele ja tenha expirado."""
    import json
    if not security.LICENSE_FILE.exists():
        return None
    try:
        data = json.loads(security.LICENSE_FILE.read_text(encoding="utf-8"))
        if data.get("machine_id"):
            return {"machine_id": data["machine_id"], "company": data.get("company", "")}
    except Exception:
        pass
    return None


def check_server_status(machine_id: str) -> bool | None:
    """
    Checa se o servidor considera este cliente ativo.
    Retorna True (ativo), False (bloqueado) ou None (sem conexao/erro).
    """
    try:
        resp = requests.get(
            f"{LICENSE_SERVER_URL}/api/status/{machine_id}",
            params={"produto": PRODUTO},
            timeout=REQUEST_TIMEOUT_SECONDS,
        )
        resp.raise_for_status()
        return bool(resp.json().get("ativo", True))
    except Exception:
        return None


def apply_server_status() -> None:
    """
    Chamado pelo scheduler a cada 5 min. Se o servidor disser bloqueado,
    cria o flag local — gate_middleware bloqueia na proxima request.
    Se disser ativo, remove o flag (desbloqueia). Se sem conexao, nao faz nada.
    """
    dados = known_activation_data()
    if not dados:
        return
    ativo = check_server_status(dados["machine_id"])
    if ativo is None:
        return  # sem internet — mantem estado atual
    if not ativo:
        security.BLOCK_FLAG_FILE.touch()
    else:
        if security.BLOCK_FLAG_FILE.exists():
            security.BLOCK_FLAG_FILE.unlink()


import time as _time

_status_cache: bool | None = None
_status_cache_at: float = 0.0
_STATUS_CACHE_TTL = 300  # 5 minutos


def is_server_blocked() -> bool:
    """Retorna True se o servidor confirmar bloqueio (cache 5 min). False em caso de duvida."""
    global _status_cache, _status_cache_at
    now = _time.monotonic()
    if _status_cache is not None and now - _status_cache_at < _STATUS_CACHE_TTL:
        return _status_cache is False
    dados = known_activation_data()
    if not dados:
        return False
    resultado = check_server_status(dados["machine_id"])
    if resultado is not None:
        _status_cache = resultado
        _status_cache_at = now
    return _status_cache is False
