"""Tool de analise — toda analise com LLM em uma unica tool (map-reduce para processos grandes)."""

import time
from typing import Any

from fastmcp import Context, FastMCP

from services.supabase_client import get_supabase_client
from services.usage_logger import get_usage_logger, ms_since
from tools._helpers import (
    MSG_PROCESSO_NAO_ENCONTRADO,
    _get_current_user,
    analisar_map_reduce,
    erro_instrutivo,
)


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

    @mcp.tool(annotations={"readOnlyHint": True, "openWorldHint": False})
    async def analisar(
        numero_processo: str,
        pergunta: str = "Faca uma analise completa deste processo",
        document_ids: str | None = None,
        perspectiva: str | None = None,
        ctx: Context = None,
    ) -> dict[str, Any]:
        """
        Ferramenta PRINCIPAL de analise — responde QUALQUER pergunta sobre um processo judicial usando LLM.

        IMPORTANTE PARA O AGENTE:
        - Esta tool e PODEROSA e pode ser chamada MULTIPLAS VEZES no mesmo processo com perguntas diferentes.
        - Ela le TODOS os documentos do processo automaticamente (sentencas, peticoes, laudos, etc.).
        - Para processos grandes (centenas de documentos), usa estrategia map-reduce: divide em lotes,
          resume cada lote em paralelo, e consolida numa resposta final. Nao ha limite de tamanho.
        - Cada chamada com uma pergunta diferente gera uma analise diferente — use sem medo.
        - Combine com visao_geral_processo() que ja inclui catalogo de documentos com IDs.
        - Obtenha IDs de documentos via visao_geral_processo() ou ls_documentos().

        ESTRATEGIA RECOMENDADA (Deep Agent):
        1. visao_geral_processo(cnj) → entender o processo
        2. analisar(cnj, "Qual a situacao atual?") → panorama geral
        3. analisar(cnj, "Quais os pedidos e seus status?") → detalhamento
        4. analisar(cnj, "Analise de risco", perspectiva="autor") → perspectiva especifica
        5. analisar(cnj, "Houve intimacao para audiencia X?") → pergunta pontual
        6. analisar(cnj, document_ids="id1,id2", pergunta="Compare") → docs especificos

        FORMATOS de uso:
        1. analisar("CNJ") → Analise completa do processo inteiro
        2. analisar("CNJ", "pergunta") → Pergunta especifica sobre o processo
        3. analisar("CNJ", document_ids="id1,id2") → Analise de documentos especificos
        4. analisar("CNJ", "pergunta", perspectiva="autor") → Analise com perspectiva orientada

        PERSPECTIVAS disponiveis:
        - Civel: "autor", "reu", "terceiro"
        - Criminal: "acusado", "ministerio_publico", "defensor", "vitima"
        - Neutro: "juiz", "assessor"

        EXEMPLOS de perguntas (chame uma por vez, quantas precisar):
        - "Qual a situacao atual? Fase, pendencias, alertas."
        - "Extraia todos os pedidos com tipo, valor e status."
        - "Analise as decisoes: fundamentacao, ratio decidendi."
        - "Analise de risco completa com cenarios."
        - "Identifique prazos proximos e urgencias."
        - "Elabore parecer juridico sobre viabilidade recursal."
        - "O reu foi citado? Quando e como?"
        - "Houve acordo ou tentativa de conciliacao?"
        - "Resuma os laudos periciais e suas conclusoes."

        RETORNO inclui metadata: estrategia (contexto_unico ou map_reduce), lotes, docs_total.

        Args:
            numero_processo: Numero CNJ do processo (formato NNNNNNN-DD.AAAA.J.TR.OOOO).
            pergunta: Pergunta ou instrucao em linguagem natural. Seja especifico para melhores resultados.
            document_ids: IDs separados por virgula para analisar docs especificos (use ls_documentos para obter IDs).
            perspectiva: Perspectiva de analise — orienta o LLM a analisar sob o ponto de vista indicado.
        """
        _start = time.perf_counter()
        user_id, user_email = _get_current_user()
        try:
            client = get_supabase_client()

            # Detecta tipo do processo
            tipo_processo = await client.detectar_tipo_processo(numero_processo)

            # --- Caminho 1: Analise de documentos especificos ---
            if document_ids:
                return await _analisar_documentos_especificos(
                    client=client,
                    numero_processo=numero_processo,
                    document_ids=document_ids,
                    pergunta=pergunta,
                    perspectiva=perspectiva,
                    tipo_processo=tipo_processo,
                    user_id=user_id,
                    user_email=user_email,
                    _start=_start,
                )

            # --- Caminho 2: Analise do processo completo ---
            return await _analisar_processo_completo(
                client=client,
                numero_processo=numero_processo,
                pergunta=pergunta,
                perspectiva=perspectiva,
                tipo_processo=tipo_processo,
                user_id=user_id,
                user_email=user_email,
                _start=_start,
            )
        except Exception as e:
            try:
                get_usage_logger().log_tool_call(
                    tool_name="analisar",
                    duration_ms=ms_since(_start),
                    user_id=user_id,
                    user_email=user_email,
                    success=False,
                    error_message=str(e),
                    params={"numero_processo": numero_processo},
                )
            except Exception:
                pass
            return erro_instrutivo(
                str(e),
                "Verifique o numero do processo e tente novamente. "
                "Se o erro persistir, reduza o escopo com document_ids.",
            )


async def _analisar_documentos_especificos(
    *,
    client: Any,
    numero_processo: str,
    document_ids: str,
    pergunta: str,
    perspectiva: str | None,
    tipo_processo: str,
    user_id: str | None,
    user_email: str | None,
    _start: float,
) -> dict[str, Any]:
    """Caminho 1: analisa documentos especificos por ID."""
    ids = [doc_id.strip() for doc_id in document_ids.split(",") if doc_id.strip()]

    if not ids:
        try:
            get_usage_logger().log_tool_call(
                tool_name="analisar",
                duration_ms=ms_since(_start),
                success=False,
                error_message="invalid_ids",
                user_id=user_id,
                user_email=user_email,
                params={"numero_processo": numero_processo, "document_ids": document_ids},
            )
        except Exception:
            pass
        return erro_instrutivo(
            "Nenhum document_id valido fornecido.",
            "Use ls_documentos(numero_processo) para obter IDs do catalogo de documentos.",
        )

    # Busca cada documento
    docs = []
    for doc_id in ids:
        doc = await client.ler_documento(doc_id)
        if doc and doc.get("conteudo"):
            docs.append(doc)

    if not docs:
        try:
            get_usage_logger().log_tool_call(
                tool_name="analisar",
                duration_ms=ms_since(_start),
                success=False,
                error_message="docs_not_found",
                user_id=user_id,
                user_email=user_email,
                params={"numero_processo": numero_processo, "document_ids": document_ids},
            )
        except Exception:
            pass
        return erro_instrutivo(
            "Nenhum dos documentos foi encontrado ou tem conteudo.",
            "Verifique os IDs com ls_documentos(numero_processo).",
        )

    # Adiciona instrucao de comparacao se 2+ docs
    pergunta_final = pergunta
    if len(docs) > 1:
        pergunta_final = (
            f"{pergunta}\n\nATENCAO: Voce recebeu {len(docs)} documentos. "
            "Compare e contraste as informacoes entre eles quando relevante."
        )

    # Map-reduce (mesmo para docs especificos, caso sejam grandes)
    resposta_text, metadata = await analisar_map_reduce(
        docs=docs,
        pergunta=pergunta_final,
        perspectiva=perspectiva,
        tipo_processo=tipo_processo,
        tool_name="analisar",
        user_id=user_id,
        user_email=user_email,
    )

    try:
        get_usage_logger().log_tool_call(
            tool_name="analisar",
            duration_ms=ms_since(_start),
            user_id=user_id,
            user_email=user_email,
            params={
                "numero_processo": numero_processo,
                "document_ids": document_ids,
                "estrategia": metadata.get("estrategia", "documentos_especificos"),
            },
        )
    except Exception:
        pass

    return {
        "sucesso": True,
        "numero_processo": numero_processo,
        "tipo_processo": tipo_processo,
        "modelo": "gemini-flash",
        "estrategia": metadata.get("estrategia", "documentos_especificos"),
        "documentos_analisados": [d.get("nome") for d in docs],
        "resposta": resposta_text,
        **{k: v for k, v in metadata.items() if k != "estrategia"},
    }


async def _analisar_processo_completo(
    *,
    client: Any,
    numero_processo: str,
    pergunta: str,
    perspectiva: str | None,
    tipo_processo: str,
    user_id: str | None,
    user_email: str | None,
    _start: float,
) -> dict[str, Any]:
    """Caminho 2: analisa processo completo via documents (map-reduce se necessario)."""
    # Busca TODOS os documentos com conteudo
    docs = await client.listar_documentos(
        numero_processo,
        limite=5000,
        incluir_preview=True,
    )

    # Filtra docs sem conteudo
    docs_com_conteudo = [d for d in docs if d.get("conteudo")]

    if not docs_com_conteudo:
        try:
            get_usage_logger().log_tool_call(
                tool_name="analisar",
                duration_ms=ms_since(_start),
                success=False,
                error_message="no_documents",
                user_id=user_id,
                user_email=user_email,
                params={"numero_processo": numero_processo},
            )
        except Exception:
            pass
        return erro_instrutivo(
            f"Processo {numero_processo} nao encontrado ou sem documentos com conteudo.",
            MSG_PROCESSO_NAO_ENCONTRADO,
        )

    # Map-reduce automatico (decide internamente se precisa dividir)
    resposta_text, metadata = await analisar_map_reduce(
        docs=docs_com_conteudo,
        pergunta=pergunta,
        perspectiva=perspectiva,
        tipo_processo=tipo_processo,
        tool_name="analisar",
        user_id=user_id,
        user_email=user_email,
    )

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

    return {
        "sucesso": True,
        "numero_processo": numero_processo,
        "tipo_processo": tipo_processo,
        "modelo": "gemini-flash",
        "resposta": resposta_text,
        **metadata,
    }
