"""
Cliente HTTP compartilhado para todas as API Tools.
Usa httpx + OAuth 1.0 via authlib.
"""
import json
import httpx
from authlib.integrations.httpx_client import AsyncOAuth1Client
from config import (
    FLUIG_SERVER,
    FLUIG_CONSUMER_KEY,
    FLUIG_CONSUMER_SECRET,
    FLUIG_ACCESS_TOKEN,
    FLUIG_TOKEN_SECRET,
    FLUIG_VERIFY_SSL,
    FLUIG_MODULE_PREFIX,
)

_TIMEOUT = 30


def _oauth_client() -> httpx.AsyncClient:
    """Cria um httpx.AsyncClient com OAuth 1.0 nativo via authlib."""
    return AsyncOAuth1Client(
        client_id=FLUIG_CONSUMER_KEY,
        client_secret=FLUIG_CONSUMER_SECRET,
        token=FLUIG_ACCESS_TOKEN,
        token_secret=FLUIG_TOKEN_SECRET,
        timeout=_TIMEOUT,
        verify=FLUIG_VERIFY_SSL,
    )


# Mapeamento de prefixos de modulo do Fluig.
# Cada path de API precisa do prefixo do modulo correspondente.
_MODULE_PREFIXES = [
    # Datasets
    ("/api/v2/datasets", "/dataset"),
    ("/api/v2/dataset-handle", "/dataset"),
    ("/api/v2/dataset-history", "/dataset"),
    # Users, Groups, Roles
    ("/api/v1/users", "/admin"),
    ("/api/v1/groups", "/admin"),
    ("/api/v1/roles", "/admin"),
    # Processes / Workflows
    ("/api/v2/processes", "/process-management"),
    ("/api/v2/activities", "/process-management"),
    ("/api/v2/date-calculator", "/process-management"),
    # Documents / Folders
    ("/api/v2/documents", "/content-management"),
    ("/api/v2/folders", "/content-management"),
    # Forms / CardIndex
    ("/api/v2/cardindex", "/ecm-forms"),
    ("/api/v2/forms", "/ecm-forms"),
    # Social / Collaboration
    ("/api/v3/communities", "/collaboration"),
    ("/api/v3/posts", "/collaboration"),
    ("/api/v3/timeline", "/collaboration"),
    ("/api/v3/articles", "/collaboration"),
    ("/api/v3/favorites", "/collaboration"),
    ("/api/v3/users", "/collaboration"),
    # Alerts
    ("/api/v2/alerts", "/collaboration"),
    # Environment / Admin
    ("/api/v2/statistics", "/environment"),
    ("/api/public/2.0/globalparameters", "/environment"),
    ("/api/public/2.0/jobs", "/environment"),
    ("/api/public/2.0/permissions", "/admin"),
    ("/api/public/2.0/substitute", "/admin"),
    # Search
    ("/api/public/2.0/search", "/content-management"),
    ("/api/public/ecm/document/search", "/content-management"),
    # Integrations
    ("/api/v2/operations", "/dataservice"),
]


def _add_module_prefix(path: str) -> str:
    """Adiciona o prefixo de modulo Fluig ao path da API."""
    if not FLUIG_MODULE_PREFIX:
        return path
    for pattern, prefix in _MODULE_PREFIXES:
        if path.startswith(pattern):
            return prefix + path
    # Se nao encontrar mapeamento, retorna o path original
    return path


def _build_url(path: str) -> str:
    return f"{FLUIG_SERVER.rstrip('/')}{_add_module_prefix(path)}"


def _error_message(status: int, body: str) -> str:
    if status == 401:
        return "Erro 401: Credenciais OAuth invalidas ou expiradas. Verifique o .env."
    if status == 403:
        return f"Erro 403: Sem permissao para este recurso. Detalhe: {body}"
    if status == 404:
        return f"Erro 404: Recurso nao encontrado. Detalhe: {body}"
    if status == 500:
        return f"Erro 500: Erro interno no servidor Fluig. Detalhe: {body}"
    return f"Erro {status}: {body}"


def _parse_response(response: httpx.Response) -> str:
    """Processa response de forma unificada para todos os metodos HTTP."""
    if response.status_code >= 400:
        return _error_message(response.status_code, response.text[:500])
    if response.status_code == 204 or not response.text:
        return json.dumps({"status": "sucesso", "mensagem": "Operacao realizada com sucesso."})
    try:
        return json.dumps(response.json(), ensure_ascii=False, indent=2)
    except (json.JSONDecodeError, ValueError):
        return response.text[:2000]


async def _request(method: str, path: str, params: dict = None, body: dict = None) -> str:
    """Executa request autenticada na API do Fluig com retry para falhas transientes."""
    url = _build_url(path)
    headers = {"Accept": "application/json"}
    if method in ("POST", "PUT", "PATCH") and body is not None:
        headers["Content-Type"] = "application/json"

    max_retries = 2
    last_error = None

    for attempt in range(max_retries + 1):
        try:
            async with _oauth_client() as client:
                response = await client.request(
                    method,
                    url,
                    params=params,
                    json=body if body is not None else None,
                    headers=headers,
                )
                # Retry apenas para erros transientes do servidor
                if response.status_code in (502, 503, 504) and attempt < max_retries:
                    import asyncio
                    await asyncio.sleep(1 * (attempt + 1))
                    continue
                return _parse_response(response)
        except httpx.TimeoutException:
            last_error = "Erro: Timeout na requisicao. O servidor Fluig demorou demais para responder."
            if attempt < max_retries:
                import asyncio
                await asyncio.sleep(1 * (attempt + 1))
                continue
        except httpx.ConnectError as e:
            err_msg = str(e).lower()
            if "ssl" in err_msg or "certificate" in err_msg or "verify" in err_msg:
                return (
                    f"Erro SSL: Falha na verificacao do certificado de {FLUIG_SERVER}. "
                    f"Se o servidor usa certificado auto-assinado, configure FLUIG_VERIFY_SSL=false no .env."
                )
            return f"Erro: Nao foi possivel conectar ao servidor {FLUIG_SERVER}. Verifique a URL no .env."
        except Exception as e:
            err_msg = str(e).lower()
            if "ssl" in err_msg or "certificate" in err_msg:
                return (
                    f"Erro SSL: {str(e)}. "
                    f"Configure FLUIG_VERIFY_SSL=false no .env para desativar verificacao SSL."
                )
            return f"Erro inesperado: {str(e)}"

    return last_error or "Erro: falha apos tentativas de retry."


async def fluig_get(path: str, params: dict = None) -> str:
    """Executa GET autenticado na API do Fluig."""
    return await _request("GET", path, params=params)


async def fluig_post(path: str, body: dict = None, params: dict = None) -> str:
    """Executa POST autenticado na API do Fluig."""
    return await _request("POST", path, params=params, body=body)


async def fluig_put(path: str, body: dict = None, params: dict = None) -> str:
    """Executa PUT autenticado na API do Fluig."""
    return await _request("PUT", path, params=params, body=body)


async def fluig_patch(path: str, body: dict = None, params: dict = None) -> str:
    """Executa PATCH autenticado na API do Fluig."""
    return await _request("PATCH", path, params=params, body=body)


async def fluig_delete(path: str, params: dict = None) -> str:
    """Executa DELETE autenticado na API do Fluig."""
    return await _request("DELETE", path, params=params)
