"""Tools de consulta — documentos e movimentacoes com eviction inteligente."""

import time
from typing import Any

from fastmcp import Context, FastMCP

from services.supabase_client import _normalize_text, get_supabase_client
from services.usage_logger import get_usage_logger, ms_since
from tools._helpers import (
    CATEGORIAS_DOCS,
    LIMIAR_EVICTION,
    MAX_DOCUMENTOS,
    MAX_MOVIMENTACOES,
    MSG_DOCUMENTO_NAO_ENCONTRADO,
    MSG_PROCESSO_NAO_ENCONTRADO,
    _extrair_snippet,
    _get_current_user,
    _smart_response,
    erro_instrutivo,
    paginar_resultado,
)


def register_consultas_tools(mcp: FastMCP) -> None:
    """Registra tools de consulta no servidor MCP."""

    @mcp.tool
    async def consultar_documentos(
        numero_processo: str | None = None,
        document_id: str | None = None,
        busca: str | None = None,
        importantes: bool = False,
        categoria: str | None = None,
        limite: int = 30,
        offset: int = 0,
        ctx: Context = None,
    ) -> dict[str, Any]:
        """
        Consulta documentos de um processo — leitura, busca, filtro ou listagem.

        Use explorar_processo() primeiro para obter o catalogo com IDs e tamanhos.

        QUANDO usar:
        - Ler conteudo de um documento especifico (por ID do catalogo)
        - Buscar termo em documentos (full-text search)
        - Filtrar documentos importantes/relevantes
        - Listar documentos com metadados

        FORMATOS de uso (dispatch automatico por parametros):
        1. consultar_documentos(document_id="uuid") → Le documento com eviction inteligente
        2. consultar_documentos(numero_processo="...", busca="sentenca") → Busca full-text
        3. consultar_documentos(numero_processo="...", importantes=True) → Docs relevantes
        4. consultar_documentos(numero_processo="...") → Lista metadados (sem conteudo)

        EVICTION: Documentos > 10k chars sao resumidos automaticamente com Gemini.
        O campo 'foi_resumido' indica se houve resumo.

        Args:
            numero_processo: Numero CNJ do processo.
            document_id: UUID do documento (obtido via explorar_processo).
            busca: Termo para busca full-text no conteudo dos documentos.
            importantes: Se True, retorna apenas documentos relevantes por prioridade.
            categoria: Filtro de categoria: "decisorio", "peticoes", "provas", "criminal".
            limite: Maximo de resultados (default 30, max 100).
            offset: Offset para paginacao.
        """
        _start = time.perf_counter()
        user_id, user_email = _get_current_user()
        client = get_supabase_client()
        limite = min(limite, MAX_DOCUMENTOS)

        # --- Caminho 1: Ler documento por ID com eviction ---
        if document_id:
            doc = await client.ler_documento(document_id)

            if not doc:
                try:
                    get_usage_logger().log_tool_call(
                        tool_name="consultar_documentos",
                        duration_ms=ms_since(_start),
                        success=False,
                        error_message="not_found",
                        user_id=user_id,
                        user_email=user_email,
                        params={"document_id": document_id},
                    )
                except Exception:
                    pass
                return erro_instrutivo(
                    f"Documento {document_id} nao encontrado.",
                    MSG_DOCUMENTO_NAO_ENCONTRADO,
                )

            conteudo = doc.get("conteudo") or ""
            tamanho_original = len(conteudo)

            # Eviction inteligente
            if tamanho_original > LIMIAR_EVICTION:
                resultado = await _smart_response(
                    conteudo,
                    tipo="documento",
                    tool_name="consultar_documentos",
                    user_id=user_id,
                    user_email=user_email,
                )
                conteudo_final = resultado["conteudo"]
                foi_resumido = resultado["foi_resumido"]
            else:
                conteudo_final = conteudo
                foi_resumido = False

            try:
                get_usage_logger().log_tool_call(
                    tool_name="consultar_documentos",
                    duration_ms=ms_since(_start),
                    user_id=user_id,
                    user_email=user_email,
                    params={"document_id": document_id},
                )
            except Exception:
                pass

            return {
                "sucesso": True,
                "id": doc.get("id"),
                "nome": doc.get("nome"),
                "tipo": doc.get("tipo_nome") or doc.get("tipo"),
                "data": doc.get("data_juntada"),
                "paginas": doc.get("paginas"),
                "tamanho_original": tamanho_original,
                "foi_resumido": foi_resumido,
                "conteudo": conteudo_final,
            }

        # Demais caminhos precisam de numero_processo
        if not numero_processo:
            try:
                get_usage_logger().log_tool_call(
                    tool_name="consultar_documentos",
                    duration_ms=ms_since(_start),
                    success=False,
                    error_message="missing_params",
                    user_id=user_id,
                    user_email=user_email,
                )
            except Exception:
                pass
            return erro_instrutivo(
                "Parametro obrigatorio ausente.",
                "Forneca document_id para ler um documento ou numero_processo para listar/buscar.",
            )

        # --- Caminho 2: Busca full-text ---
        if busca:
            resultados = await client.buscar_em_documentos(
                termo=busca,
                numero_processo=numero_processo,
                limite=limite,
                incluir_conteudo=True,
            )

            if not resultados:
                try:
                    get_usage_logger().log_tool_call(
                        tool_name="consultar_documentos",
                        duration_ms=ms_since(_start),
                        success=False,
                        error_message="not_found",
                        user_id=user_id,
                        user_email=user_email,
                        params={"numero_processo": numero_processo, "busca": busca},
                    )
                except Exception:
                    pass
                return erro_instrutivo(
                    f"Nenhum documento contem '{busca}'.",
                    "Tente termos mais genericos ou use explorar_processo() para ver o catalogo.",
                )

            items = [
                {
                    "id": r.get("id"),
                    "nome": r.get("nome") or "",
                    "tipo": r.get("tipo_nome"),
                    "snippet": _extrair_snippet(r.get("conteudo", ""), busca)
                    if r.get("conteudo")
                    else None,
                }
                for r in resultados[offset : offset + limite]
            ]

            try:
                get_usage_logger().log_tool_call(
                    tool_name="consultar_documentos",
                    duration_ms=ms_since(_start),
                    user_id=user_id,
                    user_email=user_email,
                    params={"numero_processo": numero_processo, "busca": busca},
                )
            except Exception:
                pass

            return {
                "sucesso": True,
                "numero_processo": numero_processo,
                "busca": busca,
                **paginar_resultado(items, len(resultados), limite, offset),
            }

        # --- Caminho 3: Documentos importantes ---
        if importantes:
            docs = await client.buscar_documentos_relevantes(numero_processo, limite=100)

            # Filtra por categoria se fornecida
            if categoria and categoria in CATEGORIAS_DOCS:
                termos = CATEGORIAS_DOCS[categoria]
                docs = [
                    d
                    for d in docs
                    if any(t in _normalize_text(d.get("nome") or "") for t in termos)
                ]

            if not docs:
                try:
                    get_usage_logger().log_tool_call(
                        tool_name="consultar_documentos",
                        duration_ms=ms_since(_start),
                        success=False,
                        error_message="not_found",
                        user_id=user_id,
                        user_email=user_email,
                        params={"numero_processo": numero_processo, "importantes": True},
                    )
                except Exception:
                    pass
                return erro_instrutivo(
                    "Nenhum documento relevante encontrado.",
                    "Use consultar_documentos(numero_processo=...) para ver todos os documentos.",
                )

            items = [
                {
                    "id": d.get("id"),
                    "nome": d.get("nome"),
                    "tipo": d.get("tipo_nome"),
                    "data": str(d.get("data_juntada"))[:10] if d.get("data_juntada") else None,
                    "chars": d.get("tamanho_texto"),
                    "prioridade": d.get("prioridade"),
                }
                for d in docs[offset : offset + limite]
            ]

            try:
                get_usage_logger().log_tool_call(
                    tool_name="consultar_documentos",
                    duration_ms=ms_since(_start),
                    user_id=user_id,
                    user_email=user_email,
                    params={"numero_processo": numero_processo, "importantes": True},
                )
            except Exception:
                pass

            return {
                "sucesso": True,
                "numero_processo": numero_processo,
                "categoria": categoria,
                **paginar_resultado(items, len(docs), limite, offset),
            }

        # --- Caminho 4: Lista metadados (sem conteudo) ---
        docs = await client.listar_documentos(
            numero_processo,
            limite=limite,
            ordenar_por="data",
            incluir_preview=False,
        )

        if not docs:
            try:
                get_usage_logger().log_tool_call(
                    tool_name="consultar_documentos",
                    duration_ms=ms_since(_start),
                    success=False,
                    error_message="not_found",
                    user_id=user_id,
                    user_email=user_email,
                    params={"numero_processo": numero_processo},
                )
            except Exception:
                pass
            return erro_instrutivo(
                f"Nenhum documento encontrado para {numero_processo}.",
                MSG_PROCESSO_NAO_ENCONTRADO,
            )

        items = [
            {
                "id": d.get("id"),
                "nome": d.get("nome") or "",
                "tipo": d.get("tipo_nome"),
                "data": d.get("data_juntada"),
                "chars": d.get("tamanho_texto"),
            }
            for d in docs[offset : offset + limite]
        ]

        try:
            get_usage_logger().log_tool_call(
                tool_name="consultar_documentos",
                duration_ms=ms_since(_start),
                user_id=user_id,
                user_email=user_email,
                params={"numero_processo": numero_processo},
            )
        except Exception:
            pass

        return {
            "sucesso": True,
            "numero_processo": numero_processo,
            **paginar_resultado(items, len(docs), limite, offset),
        }

    @mcp.tool
    async def consultar_movimentacoes(
        numero_processo: str | None = None,
        busca: str | None = None,
        tipo: str | None = None,
        limite: int = 50,
        offset: int = 0,
        ctx: Context = None,
    ) -> dict[str, Any]:
        """
        Consulta movimentacoes processuais — busca, filtro ou listagem.

        Use explorar_processo() primeiro para ver tipos de movimentacoes disponiveis.

        QUANDO usar:
        - Ver timeline/historico de um processo
        - Buscar movimentacao especifica por termo
        - Filtrar movimentacoes por tipo
        - Ver movimentacoes recentes de todos os processos

        FORMATOS de uso (dispatch automatico por parametros):
        1. consultar_movimentacoes(numero_processo="...", busca="sentenca") → Busca por termo
        2. consultar_movimentacoes(numero_processo="...", tipo="Juntada") → Filtro por tipo
        3. consultar_movimentacoes(numero_processo="...") → Timeline completa
        4. consultar_movimentacoes() → Recentes de todos os processos

        Args:
            numero_processo: Numero CNJ do processo (se omitido, mostra recentes globais).
            busca: Termo para buscar na descricao das movimentacoes.
            tipo: Tipo de movimentacao para filtrar (ex: "Juntada", "Despacho").
            limite: Maximo de resultados (default 50, max 100).
            offset: Offset para paginacao.
        """
        _start = time.perf_counter()
        user_id, user_email = _get_current_user()
        client = get_supabase_client()
        limite = min(limite, MAX_MOVIMENTACOES)

        # --- Caminho 1: Busca por termo ---
        if numero_processo and busca:
            resultados = await client.buscar_movimentacoes_por_termo(
                numero_processo, busca, limite=limite
            )

            if not resultados:
                try:
                    get_usage_logger().log_tool_call(
                        tool_name="consultar_movimentacoes",
                        duration_ms=ms_since(_start),
                        success=False,
                        error_message="not_found",
                        user_id=user_id,
                        user_email=user_email,
                        params={"numero_processo": numero_processo, "busca": busca},
                    )
                except Exception:
                    pass
                return erro_instrutivo(
                    f"Nenhuma movimentacao contem '{busca}'.",
                    "Tente termos mais genericos ou use consultar_movimentacoes(numero_processo=...) para ver todas.",
                )

            items = [
                {
                    "data": m.get("data_hora"),
                    "tipo": m.get("tipo_nome"),
                    "descricao": m.get("descricao"),
                }
                for m in resultados[offset : offset + limite]
            ]

            try:
                get_usage_logger().log_tool_call(
                    tool_name="consultar_movimentacoes",
                    duration_ms=ms_since(_start),
                    user_id=user_id,
                    user_email=user_email,
                    params={"numero_processo": numero_processo, "busca": busca},
                )
            except Exception:
                pass

            return {
                "sucesso": True,
                "numero_processo": numero_processo,
                "busca": busca,
                **paginar_resultado(items, len(resultados), limite, offset),
            }

        # --- Caminho 2 e 3: Listar com filtro opcional por tipo ---
        if numero_processo:
            resultados = await client.listar_movimentacoes(
                numero_processo, tipo=tipo, limite=limite
            )

            if not resultados:
                msg = f"Nenhuma movimentacao encontrada para {numero_processo}"
                if tipo:
                    msg += f" com tipo '{tipo}'"
                try:
                    get_usage_logger().log_tool_call(
                        tool_name="consultar_movimentacoes",
                        duration_ms=ms_since(_start),
                        success=False,
                        error_message="not_found",
                        user_id=user_id,
                        user_email=user_email,
                        params={"numero_processo": numero_processo, "tipo": tipo},
                    )
                except Exception:
                    pass
                return erro_instrutivo(
                    msg + ".",
                    MSG_PROCESSO_NAO_ENCONTRADO if not tipo else "Tente sem filtro de tipo.",
                )

            items = [
                {
                    "data": m.get("data_hora"),
                    "tipo": m.get("tipo_nome"),
                    "descricao": m.get("descricao"),
                }
                for m in resultados[offset : offset + limite]
            ]

            try:
                get_usage_logger().log_tool_call(
                    tool_name="consultar_movimentacoes",
                    duration_ms=ms_since(_start),
                    user_id=user_id,
                    user_email=user_email,
                    params={"numero_processo": numero_processo, "tipo": tipo},
                )
            except Exception:
                pass

            return {
                "sucesso": True,
                "numero_processo": numero_processo,
                "tipo_filtro": tipo,
                **paginar_resultado(items, len(resultados), limite, offset),
            }

        # --- Caminho 4: Recentes de todos os processos ---
        resultados = await client.movimentacoes_recentes(limite=limite)

        if not resultados:
            try:
                get_usage_logger().log_tool_call(
                    tool_name="consultar_movimentacoes",
                    duration_ms=ms_since(_start),
                    success=False,
                    error_message="empty",
                    user_id=user_id,
                    user_email=user_email,
                )
            except Exception:
                pass
            return erro_instrutivo(
                "Nenhuma movimentacao recente encontrada.",
                "Sincronize processos primeiro.",
            )

        items = [
            {
                "numero_processo": m.get("numero_processo"),
                "data": m.get("data_hora"),
                "tipo": m.get("tipo_nome"),
                "descricao": m.get("descricao"),
            }
            for m in resultados[offset : offset + limite]
        ]

        try:
            get_usage_logger().log_tool_call(
                tool_name="consultar_movimentacoes",
                duration_ms=ms_since(_start),
                user_id=user_id,
                user_email=user_email,
            )
        except Exception:
            pass

        return {
            "sucesso": True,
            **paginar_resultado(items, len(resultados), limite, offset),
        }
