# -*- coding: utf-8 -*-
# mcp_server.py
import json
import logging
import os
import sys
from typing import Literal, Optional

import requests
from mcp.server.fastmcp import FastMCP

from config import settings

LOG_LEVEL = logging.DEBUG if settings.DEBUG else logging.INFO
logging.basicConfig(
    level=LOG_LEVEL,
    format="%(asctime)s - %(levelname)s - %(message)s",
    stream=sys.stderr,
)
logger = logging.getLogger("ZEMPO_MCP")

mcp = FastMCP("Zempo_Sports_MCP")

USER_ZEMPO_TOKEN = os.getenv("USER_ZEMPO_TOKEN", "")
REQUEST_TIMEOUT = 45
DEFAULT_LIMIT = 30


def otimizar_para_ia(dados, limite_itens=DEFAULT_LIMIT):
    """
    Remove campos vazios e limita o tamanho de listas para evitar respostas
    excessivamente grandes para a IA.
    """
    if isinstance(dados, dict):
        novo_dict = {}
        for k, v in dados.items():
            if isinstance(v, list):
                v_limpo = [otimizar_para_ia(item) for item in v[:limite_itens]]
                novo_dict[k] = v_limpo
                if len(v) > limite_itens:
                    novo_dict["_meta_info"] = (
                        f"Aviso: A pesquisa encontrou {len(v)} resultados. "
                        f"Apenas os primeiros {limite_itens} foram enviados à IA."
                    )
            else:
                v_limpo = otimizar_para_ia(v)
                if v_limpo or v_limpo == 0 or v_limpo is False:
                    novo_dict[k] = v_limpo
        return novo_dict
    if isinstance(dados, list):
        return [otimizar_para_ia(item) for item in dados[:limite_itens]]
    return dados


def _resolve_api_token() -> str:
    """
    Usa preferencialmente um token explícito da API nova e, como fallback,
    reaproveita o token injetado no subprocesso.
    """
    configured_token = getattr(settings, "API_TOKEN", "") or os.getenv("API_TOKEN", "")
    return configured_token or USER_ZEMPO_TOKEN


def _parse_json_filters(filtros_json: Optional[str]) -> dict:
    if not filtros_json:
        return {}
    try:
        parsed = json.loads(filtros_json)
    except json.JSONDecodeError as exc:
        raise ValueError("filtros_json deve ser um JSON válido.") from exc
    if not isinstance(parsed, dict):
        raise ValueError("filtros_json deve representar um objeto JSON.")
    return parsed


def _normalize_scalar(value):
    if isinstance(value, bool):
        return "1" if value else "0"
    if value is None:
        return None
    return str(value)


def _prepare_params(params: Optional[dict] = None, filtros_json: Optional[str] = None) -> dict:
    merged = {}
    if params:
        merged.update(params)
    if filtros_json:
        merged.update(_parse_json_filters(filtros_json))

    prepared = {}
    for key, value in merged.items():
        if value is None or value == "":
            continue

        if isinstance(value, (list, tuple)):
            normalized_items = [_normalize_scalar(item) for item in value if item is not None and item != ""]
            if normalized_items:
                prepared[key] = normalized_items
            continue

        prepared[key] = _normalize_scalar(value)

    return prepared


def zempo_get(endpoint: str, params: Optional[dict] = None, filtros_json: Optional[str] = None) -> str:
    """
    Função base para consultar a API Flask nova via GET /api/... com Bearer token.
    """
    token = _resolve_api_token()
    if not token:
        return json.dumps(
            {
                "error": "unauthorized",
                "message": (
                    "Token da API ausente. Defina API_TOKEN ou injete "
                    "USER_ZEMPO_TOKEN no subprocesso."
                ),
            }
        )

    base = settings.API_BASE_URL.rstrip("/")
    path = endpoint.lstrip("/")
    url = f"{base}/{path}"
    try:
        query_params = _prepare_params(params=params, filtros_json=filtros_json)
    except ValueError as exc:
        return json.dumps({"error": "invalid_params", "message": str(exc)})
    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "application/json",
    }

    logger.debug("🌐 [MCP -> API] GET %s", url)
    logger.debug("↳ Query params: %s", query_params)

    try:
        response = requests.get(
            url,
            headers=headers,
            params=query_params,
            timeout=REQUEST_TIMEOUT,
        )

        if response.status_code != 200:
            logger.error("❌ [API -> MCP] ERRO %s: %s", response.status_code, response.text)
            return json.dumps({"error": response.status_code, "message": response.text})

        dados_json = response.json()
        dados_otimizados = otimizar_para_ia(dados_json, limite_itens=DEFAULT_LIMIT)
        resumo_log = str(dados_otimizados)
        if len(resumo_log) > 1000:
            resumo_log = resumo_log[:1000] + "... [TRUNCADO NO LOG]"
        logger.debug("✅ [API -> MCP] DADOS OTIMIZADOS: %s", resumo_log)
        return json.dumps(dados_otimizados, ensure_ascii=False)
    except Exception as exc:
        logger.error("🔥 [MCP -> API] FALHA NA REQUISIÇÃO: %s", exc)
        return json.dumps({"error": "request_failed", "message": str(exc)})


def zempo_post(endpoint: str, params: Optional[dict] = None) -> str:
    """
    Alias de compatibilidade. A API nova usa GET.
    """
    return zempo_get(endpoint, params=params)


def _resource_list(resource_name: str, params: Optional[dict] = None, filtros_json: Optional[str] = None) -> str:
    return zempo_get(f"/api/resources/{resource_name}", params=params, filtros_json=filtros_json)


def _resource_detail(resource_name: str, item_id: str) -> str:
    return zempo_get(f"/api/resources/{resource_name}/{item_id}")


def _resource_summary(resource_name: str, params: Optional[dict] = None, filtros_json: Optional[str] = None) -> str:
    return zempo_get(
        f"/api/resources/{resource_name}/stats/summary",
        params=params,
        filtros_json=filtros_json,
    )


def _resource_group_by(
    resource_name: str,
    field_name: str,
    params: Optional[dict] = None,
    filtros_json: Optional[str] = None,
) -> str:
    return zempo_get(
        f"/api/resources/{resource_name}/stats/group-by/{field_name}",
        params=params,
        filtros_json=filtros_json,
    )


def _resource_time_series(resource_name: str, params: Optional[dict] = None, filtros_json: Optional[str] = None) -> str:
    return zempo_get(
        f"/api/resources/{resource_name}/stats/time-series",
        params=params,
        filtros_json=filtros_json,
    )


@mcp.tool()
def zempo_api_visao_geral() -> str:
    """Retorna a visão geral da API nova: grupos, quantidade de recursos e operadores suportados."""
    return zempo_get("/api/meta/overview")


@mcp.tool()
def zempo_api_grupos() -> str:
    """Lista os grupos disponíveis na API nova."""
    return zempo_get("/api/meta/groups")


@mcp.tool()
def zempo_api_recursos(group: Optional[str] = None) -> str:
    """Lista os recursos disponíveis. Use o filtro group para restringir por grupo."""
    return zempo_get("/api/meta/resources", params={"group": group})


@mcp.tool()
def zempo_api_recurso(resource_name: str) -> str:
    """Retorna os metadados de um recurso específico da API nova."""
    return zempo_get(f"/api/meta/resources/{resource_name}")


@mcp.tool()
def zempo_api_catalogos() -> str:
    """Lista os catálogos disponíveis na API nova."""
    return zempo_get("/api/catalogs")


@mcp.tool()
def zempo_api_consultar_catalogo(
    catalog_name: str,
    q: Optional[str] = None,
    fields: Optional[str] = None,
    sort_by: Optional[str] = None,
    sort_order: Optional[Literal["asc", "desc"]] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    offset: Optional[int] = None,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta um catálogo por nome com filtros e paginação."""
    params = {
        "q": q,
        "fields": fields,
        "sort_by": sort_by,
        "sort_order": sort_order,
        "limit": limit,
        "offset": offset,
    }
    return zempo_get(f"/api/catalogs/{catalog_name}", params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_api_listar_recurso(
    resource_name: str,
    q: Optional[str] = None,
    fields: Optional[str] = None,
    sort_by: Optional[str] = None,
    sort_order: Optional[Literal["asc", "desc"]] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    offset: Optional[int] = None,
    filtros_json: Optional[str] = None,
) -> str:
    """
    Consulta qualquer recurso da API nova.
    Use filtros_json para operadores dinâmicos como:
    {"competicao":"3742","status":"1","data_cadastro__gte":"2025-01-01"}.
    """
    params = {
        "q": q,
        "fields": fields,
        "sort_by": sort_by,
        "sort_order": sort_order,
        "limit": limit,
        "offset": offset,
    }
    return _resource_list(resource_name, params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_api_detalhar_recurso(resource_name: str, item_id: str) -> str:
    """Consulta um registro específico por ID em qualquer recurso da API nova."""
    return _resource_detail(resource_name, item_id)


@mcp.tool()
def zempo_api_resumo_recurso(
    resource_name: str,
    q: Optional[str] = None,
    filtros_json: Optional[str] = None,
) -> str:
    """Retorna o resumo estatístico de um recurso da API nova."""
    return _resource_summary(resource_name, params={"q": q}, filtros_json=filtros_json)


@mcp.tool()
def zempo_api_agrupar_recurso(
    resource_name: str,
    field_name: str,
    top: Optional[int] = 20,
    q: Optional[str] = None,
    filtros_json: Optional[str] = None,
) -> str:
    """Agrupa um recurso da API nova por um campo explícito."""
    return _resource_group_by(
        resource_name,
        field_name,
        params={"top": top, "q": q},
        filtros_json=filtros_json,
    )


@mcp.tool()
def zempo_api_serie_temporal_recurso(
    resource_name: str,
    date_field: Optional[str] = None,
    granularity: Optional[Literal["day", "month", "year"]] = "month",
    q: Optional[str] = None,
    filtros_json: Optional[str] = None,
) -> str:
    """Retorna uma série temporal para um recurso da API nova."""
    return _resource_time_series(
        resource_name,
        params={
            "date_field": date_field,
            "granularity": granularity,
            "q": q,
        },
        filtros_json=filtros_json,
    )


@mcp.tool()
def zempo_pessoas(
    id: Optional[str] = None,
    codigo: Optional[str] = None,
    nome: Optional[str] = None,
    email: Optional[str] = None,
    telefone: Optional[str] = None,
    tipo_atleta: Optional[Literal["0", "1"]] = None,
    tipo_tecnico: Optional[Literal["0", "1"]] = None,
    tipo_arbitro: Optional[Literal["0", "1"]] = None,
    situacao_cbj: Optional[str] = None,
    situacao_federacao: Optional[str] = None,
    status: Optional[str] = None,
    q: Optional[str] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta o recurso pessoas da API nova usando colunas reais do schema."""
    params = {
        "id": id,
        "codigo": codigo,
        "nome": nome,
        "email": email,
        "telefone": telefone,
        "tipo_atleta": tipo_atleta,
        "tipo_tecnico": tipo_tecnico,
        "tipo_arbitro": tipo_arbitro,
        "situacao_cbj": situacao_cbj,
        "situacao_federacao": situacao_federacao,
        "status": status,
        "q": q,
        "limit": limit,
    }
    return _resource_list("pessoas", params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_federacoes(
    id: Optional[str] = None,
    codigo: Optional[str] = None,
    nome: Optional[str] = None,
    sigla: Optional[str] = None,
    estado: Optional[str] = None,
    status: Optional[str] = None,
    q: Optional[str] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta o recurso federacoes da API nova."""
    params = {
        "id": id,
        "codigo": codigo,
        "nome": nome,
        "sigla": sigla,
        "estado": estado,
        "status": status,
        "q": q,
        "limit": limit,
    }
    return _resource_list("federacoes", params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_clubes(
    id: Optional[str] = None,
    codigo: Optional[str] = None,
    nome: Optional[str] = None,
    sigla: Optional[str] = None,
    federacao: Optional[str] = None,
    status: Optional[str] = None,
    federado: Optional[Literal["0", "1"]] = None,
    cbc: Optional[Literal["0", "1"]] = None,
    q: Optional[str] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta o recurso clubes da API nova."""
    params = {
        "id": id,
        "codigo": codigo,
        "nome": nome,
        "sigla": sigla,
        "federacao": federacao,
        "status": status,
        "federado": federado,
        "cbc": cbc,
        "q": q,
        "limit": limit,
    }
    return _resource_list("clubes", params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_competicoes(
    id: Optional[str] = None,
    codigo: Optional[str] = None,
    nome: Optional[str] = None,
    tipo: Optional[str] = None,
    ambito: Optional[str] = None,
    status: Optional[str] = None,
    restrita: Optional[Literal["0", "1"]] = None,
    q: Optional[str] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta o recurso competicoes da API nova."""
    params = {
        "id": id,
        "codigo": codigo,
        "nome": nome,
        "tipo": tipo,
        "ambito": ambito,
        "status": status,
        "restrita": restrita,
        "q": q,
        "limit": limit,
    }
    return _resource_list("competicoes", params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_competicoes_categorias(
    id: Optional[str] = None,
    competicao: Optional[str] = None,
    classe: Optional[str] = None,
    sexo: Optional[str] = None,
    categoria: Optional[str] = None,
    nome: Optional[str] = None,
    q: Optional[str] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta o recurso competicoes_categorias da API nova."""
    params = {
        "id": id,
        "competicao": competicao,
        "classe": classe,
        "sexo": sexo,
        "categoria": categoria,
        "nome": nome,
        "q": q,
        "limit": limit,
    }
    return _resource_list("competicoes_categorias", params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_competicoes_inscricoes(
    id: Optional[str] = None,
    atleta: Optional[str] = None,
    categoria: Optional[str] = None,
    competicao: Optional[str] = None,
    credenciado: Optional[Literal["0", "1"]] = None,
    pago: Optional[Literal["0", "1"]] = None,
    equipe: Optional[str] = None,
    federacao_equipe: Optional[str] = None,
    q: Optional[str] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta o recurso competicoes_inscricoes da API nova."""
    params = {
        "id": id,
        "atleta": atleta,
        "categoria": categoria,
        "competicao": competicao,
        "credenciado": credenciado,
        "pago": pago,
        "equipe": equipe,
        "federacao_equipe": federacao_equipe,
        "q": q,
        "limit": limit,
    }
    return _resource_list("competicoes_inscricoes", params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_competicoes_lutas(
    id: Optional[str] = None,
    competicao: Optional[str] = None,
    categoria: Optional[str] = None,
    sexo: Optional[str] = None,
    rodada: Optional[str] = None,
    encerrada: Optional[Literal["0", "1"]] = None,
    vencedor: Optional[str] = None,
    competidor1: Optional[str] = None,
    competidor2: Optional[str] = None,
    q: Optional[str] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta o recurso competicoes_lutas da API nova."""
    params = {
        "id": id,
        "competicao": competicao,
        "categoria": categoria,
        "sexo": sexo,
        "rodada": rodada,
        "encerrada": encerrada,
        "vencedor": vencedor,
        "competidor1": competidor1,
        "competidor2": competidor2,
        "q": q,
        "limit": limit,
    }
    return _resource_list("competicoes_lutas", params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_competicoes_lutas_ocorrencias(
    id: Optional[str] = None,
    luta: Optional[str] = None,
    competicao: Optional[str] = None,
    categoria: Optional[str] = None,
    competidor: Optional[str] = None,
    golpe: Optional[str] = None,
    tipo: Optional[str] = None,
    q: Optional[str] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta o recurso competicoes_lutas_ocorrencias da API nova."""
    params = {
        "id": id,
        "luta": luta,
        "competicao": competicao,
        "categoria": categoria,
        "competidor": competidor,
        "golpe": golpe,
        "tipo": tipo,
        "q": q,
        "limit": limit,
    }
    return _resource_list("competicoes_lutas_ocorrencias", params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_competicoes_equipe_combates(
    id: Optional[str] = None,
    competicao: Optional[str] = None,
    luta: Optional[str] = None,
    categoria: Optional[str] = None,
    sexo: Optional[str] = None,
    rodada: Optional[str] = None,
    encerrada: Optional[Literal["0", "1"]] = None,
    vencedor: Optional[str] = None,
    q: Optional[str] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta o recurso competicoes_equipe_combates da API nova."""
    params = {
        "id": id,
        "competicao": competicao,
        "luta": luta,
        "categoria": categoria,
        "sexo": sexo,
        "rodada": rodada,
        "encerrada": encerrada,
        "vencedor": vencedor,
        "q": q,
        "limit": limit,
    }
    return _resource_list("competicoes_equipe_combates", params=params, filtros_json=filtros_json)


@mcp.tool()
def zempo_competicoes_equipe_combates_ocorrencias(
    id: Optional[str] = None,
    luta: Optional[str] = None,
    competicao: Optional[str] = None,
    categoria: Optional[str] = None,
    competidor: Optional[str] = None,
    golpe: Optional[str] = None,
    tipo: Optional[str] = None,
    q: Optional[str] = None,
    limit: Optional[int] = DEFAULT_LIMIT,
    filtros_json: Optional[str] = None,
) -> str:
    """Consulta o recurso competicoes_equipe_combates_ocorrencias da API nova."""
    params = {
        "id": id,
        "luta": luta,
        "competicao": competicao,
        "categoria": categoria,
        "competidor": competidor,
        "golpe": golpe,
        "tipo": tipo,
        "q": q,
        "limit": limit,
    }
    return _resource_list(
        "competicoes_equipe_combates_ocorrencias",
        params=params,
        filtros_json=filtros_json,
    )


if __name__ == "__main__":
    mcp.run(transport="stdio")
