"""Tools de precedentes — consulta ao Banco Nacional de Precedentes (BNP/CNJ)."""

import logging
import re
import time
from typing import Any

import httpx
from fastmcp import FastMCP

from services.usage_logger import get_usage_logger, ms_since
from tools._helpers import _get_current_user, erro_instrutivo, paginar_resultado

logger = logging.getLogger("tecjustica-mcp.precedentes")

_BNP_BASE_URL = "https://pangeabnp.pdpj.jus.br/api/v1/precedentes"
_BNP_TIMEOUT = 30
_BNP_HEADERS = {
    "Accept": "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "Origin": "https://bnp.pdpj.jus.br",
    "Referer": "https://bnp.pdpj.jus.br/",
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/137.0.0.0 Safari/537.36"
    ),
}

# fmt: off
# Codigos reais da API BNP (zero-padded para TRFs/TRTs, TJDF sem o T final)
_TODOS_ORGAOS: list[str] = [
    "STF", "STJ", "TST", "TSE", "STM", "CSJT", "CJF", "TNU",
    "TJAC", "TJAL", "TJAM", "TJAP", "TJBA", "TJCE", "TJDF",
    "TJES", "TJGO", "TJMA", "TJMG", "TJMS", "TJMT", "TJPA",
    "TJPB", "TJPE", "TJPI", "TJPR", "TJRJ", "TJRN", "TJRO",
    "TJRR", "TJRS", "TJSC", "TJSE", "TJSP", "TJTO",
    "TRF01", "TRF02", "TRF03", "TRF04", "TRF05", "TRF06",
    "TRT01", "TRT02", "TRT03", "TRT04", "TRT05", "TRT06",
    "TRT07", "TRT08", "TRT09", "TRT10", "TRT11", "TRT12",
    "TRT13", "TRT14", "TRT15", "TRT16", "TRT17", "TRT18",
    "TRT19", "TRT20", "TRT21", "TRT22", "TRT23", "TRT24",
]

# Codigos reais de tipos da API BNP
_TODOS_TIPOS: list[str] = [
    "SUM",   # Sumula
    "SV",    # Sumula Vinculante
    "RG",    # Repercussao Geral
    "RR",    # Recursos Repetitivos
    "IRDR",  # Incidente de Resolucao de Demandas Repetitivas
    "IAC",   # Incidente de Assuncao de Competencia
    "CT",    # Controvérsia Trabalhista
    "ADI",   # Acao Direta de Inconstitucionalidade
    "ADPF",  # Arguicao de Descumprimento de Preceito Fundamental
    "OJE",   # Orientacao Jurisprudencial - SDI Especial
    "OJSDI1",  # Orientacao Jurisprudencial - SDI 1
    "OJSDI2",  # Orientacao Jurisprudencial - SDI 2
    "OJSDI1T", # Orientacao Jurisprudencial - SDI 1 Transitoria
]
# fmt: on

_RE_HTML_TAGS = re.compile(r"<[^>]+>")


def _limpar_html(texto: str) -> str:
    """Remove tags HTML e normaliza espacos."""
    if not texto:
        return ""
    limpo = _RE_HTML_TAGS.sub("", texto)
    limpo = limpo.replace("&nbsp;", " ").replace("&amp;", "&")
    limpo = re.sub(r"\s+", " ", limpo).strip()
    return limpo


def register_precedentes_tools(mcp: FastMCP) -> None:
    """Registra tools de precedentes (BNP/CNJ)."""

    @mcp.tool(annotations={"readOnlyHint": True, "openWorldHint": True})
    async def buscar_precedentes(
        busca: str,
        orgaos: list[str] | None = None,
        tipos: list[str] | None = None,
        pagina: int = 1,
        tamanho_pagina: int = 20,
    ) -> dict[str, Any]:
        """
        Busca precedentes no Banco Nacional de Precedentes (BNP/CNJ/PDPJ).

        Consulta a API publica do BNP para encontrar sumulas, repercussao geral,
        IRDR, IRR, temas repetitivos e outros precedentes de todos os tribunais.

        QUANDO USAR:
        - Encontrar sumulas sobre um tema ("dano moral", "honorarios")
        - Buscar teses de repercussao geral ou temas repetitivos
        - Pesquisar precedentes de um tribunal especifico
        - Complementar analise processual com jurisprudencia consolidada
        - Verificar se existe sumula vinculante sobre determinada materia

        QUANDO NAO USAR:
        - Quer consultar um processo especifico → use visao_geral_processo()
        - Quer buscar dentro de documentos do processo → use grep_documentos()
        - Quer analisar processo com LLM → use analisar()

        Args:
            busca: Termo de busca em linguagem natural (ex: "dano moral", "honorarios advocaticios").
            orgaos: Filtrar por orgaos (ex: ["STJ", "STF"]). Se omitido, busca em todos.
                Valores: STF, STJ, TST, TSE, STM, CSJT, CJF,
                TJAC-TJTO (27 TJs), TRF1-TRF6, TRT1-TRT24.
            tipos: Filtrar por tipos de precedente. Se omitido, busca todos.
                Valores: SUM (Sumula), SV (Sumula Vinculante), RG (Repercussao Geral),
                RR (Recursos Repetitivos), IRDR, IAC (Assuncao de Competencia),
                CT (Controversia Trabalhista), ADI, ADPF,
                OJE, OJSDI1, OJSDI2, OJSDI1T (Orientacoes Jurisprudenciais).
            pagina: Pagina de resultados (default 1).
            tamanho_pagina: Resultados por pagina (default 20, max 100).

        Returns:
            Precedentes encontrados com teses, orgao, tipo, situacao e processos paradigma.
        """
        _start = time.perf_counter()
        user_id, user_email = _get_current_user()

        if not busca or not busca.strip():
            return erro_instrutivo(
                "Parametro 'busca' e obrigatorio.",
                "Informe um termo de busca, ex: buscar_precedentes(busca='dano moral').",
            )

        tamanho_pagina = min(max(tamanho_pagina, 1), 100)

        payload = {
            "filtro": {
                "buscaGeral": busca.strip(),
                "todasPalavras": "",
                "quaisquerPalavras": "",
                "semPalavras": "",
                "trechoExato": "",
                "atualizacaoDesde": "",
                "atualizacaoAte": "",
                "cancelados": False,
                "ordenacao": "Text",
                "nr": "",
                "pagina": pagina,
                "tamanhoPagina": tamanho_pagina,
                "orgaos": orgaos if orgaos is not None else _TODOS_ORGAOS,
                "tipos": tipos if tipos is not None else _TODOS_TIPOS,
            }
        }

        try:
            async with httpx.AsyncClient(timeout=_BNP_TIMEOUT, headers=_BNP_HEADERS) as client:
                response = await client.post(_BNP_BASE_URL, json=payload)
                response.raise_for_status()
                data = response.json()

            # Extrair resultados (campos reais da API BNP)
            precedentes_raw = data.get("resultados", [])
            total = data.get("total", len(precedentes_raw))

            # Processar cada precedente
            resultados: list[dict[str, Any]] = []
            for prec in precedentes_raw:
                # Limpar tese (vem com HTML)
                tese = _limpar_html(prec.get("tese", ""))

                # Simplificar processos paradigma
                paradigmas: list[dict[str, str]] = []
                for proc in prec.get("processosParadigma", [])[:5]:
                    paradigmas.append(
                        {
                            "nome": proc.get("nome", ""),
                            "numero": proc.get("numero", ""),
                        }
                    )

                resultados.append(
                    {
                        "id": prec.get("id", ""),
                        "orgao": prec.get("orgao", ""),
                        "tipo": prec.get("tipo", ""),
                        "nr": prec.get("nr"),
                        "situacao": prec.get("situacao", ""),
                        "tese": tese,
                        "ultima_atualizacao": prec.get("ultimaAtualizacao", ""),
                        "processos_paradigma": paradigmas,
                        "missing": prec.get("missing", []),
                    }
                )

            # Montar resposta com agregacoes
            resp = paginar_resultado(
                items=resultados,
                total=total,
                limite=tamanho_pagina,
                offset=(pagina - 1) * tamanho_pagina,
            )

            # Agregacoes da API (aggsEspecies, aggsOrgaos)
            aggs_tipos = data.get("aggsEspecies", [])
            aggs_orgaos = data.get("aggsOrgaos", [])
            if aggs_tipos or aggs_orgaos:
                resp["agregacoes"] = {
                    "tipos": {a["tipo"]: a["total"] for a in aggs_tipos},
                    "orgaos": {a["tipo"]: a["total"] for a in aggs_orgaos},
                }

            try:
                get_usage_logger().log_tool_call(
                    tool_name="buscar_precedentes",
                    duration_ms=ms_since(_start),
                    user_id=user_id,
                    user_email=user_email,
                    params={
                        "busca": busca,
                        "orgaos": orgaos,
                        "tipos": tipos,
                        "pagina": pagina,
                    },
                )
            except Exception:
                pass

            return resp

        except httpx.TimeoutException:
            try:
                get_usage_logger().log_tool_call(
                    tool_name="buscar_precedentes",
                    duration_ms=ms_since(_start),
                    user_id=user_id,
                    user_email=user_email,
                    success=False,
                    error_message="timeout",
                    params={"busca": busca},
                )
            except Exception:
                pass
            return erro_instrutivo(
                "Timeout ao consultar o BNP (>30s).",
                "Tente uma busca mais especifica ou reduza o tamanho_pagina.",
            )
        except httpx.HTTPStatusError as e:
            try:
                get_usage_logger().log_tool_call(
                    tool_name="buscar_precedentes",
                    duration_ms=ms_since(_start),
                    user_id=user_id,
                    user_email=user_email,
                    success=False,
                    error_message=f"HTTP {e.response.status_code}",
                    params={"busca": busca},
                )
            except Exception:
                pass
            return erro_instrutivo(
                f"Erro HTTP {e.response.status_code} ao consultar o BNP.",
                "A API do BNP pode estar temporariamente indisponivel. Tente novamente.",
            )
        except Exception as e:
            logger.exception("Erro inesperado em buscar_precedentes")
            try:
                get_usage_logger().log_tool_call(
                    tool_name="buscar_precedentes",
                    duration_ms=ms_since(_start),
                    user_id=user_id,
                    user_email=user_email,
                    success=False,
                    error_message=str(e),
                    params={"busca": busca},
                )
            except Exception:
                pass
            return erro_instrutivo(
                str(e),
                "Verifique os parametros e tente novamente.",
            )
