"""Tools para consulta de documentos processuais."""

from typing import Any

from fastmcp import Context, FastMCP

from services.llm_service import get_llm_service
from services.supabase_client import _normalize_text, get_supabase_client

# Limites para respostas compactas
MAX_DOCS_LISTA = 100  # Era: 20
MAX_DOCS_BUSCA = 50  # Era: 15
MAX_CHARS_PREVIEW = 500

# Categorias de documentos para filtro inteligente
CATEGORIAS_DOCS = {
    "decisorio": ["sentenc", "acordao", "acord", "decisao", "decis", "despacho"],
    "peticoes": ["petic", "petio", "inicial", "contest", "replica", "recurso", "agravo"],
    "provas": ["laudo", "pericia", "certid", "documento", "comprova"],
    "criminal": ["denunc", "denncia", "inquer", "inqurito", "defesa"],
}


def _extrair_snippet(conteudo: str, termo: str, chars: int = 200) -> str:
    """Extrai snippet ao redor do termo encontrado."""
    termo_lower = termo.lower()
    conteudo_lower = conteudo.lower()

    pos = conteudo_lower.find(termo_lower)
    if pos == -1:
        return conteudo[:chars] + "..."

    inicio = max(0, pos - chars // 2)
    fim = min(len(conteudo), pos + len(termo) + chars // 2)

    snippet = conteudo[inicio:fim]
    if inicio > 0:
        snippet = "..." + snippet
    if fim < len(conteudo):
        snippet = snippet + "..."

    return snippet


def _montar_contexto_documentos(docs: list[dict], max_chars: int = 7_000_000) -> str:
    """Monta contexto formatado para Gemini/Grok."""
    partes = []
    chars = 0

    for doc in docs:
        nome = doc.get("nome") or "Documento"
        tipo = doc.get("tipo_nome") or ""
        data = str(doc.get("data_juntada"))[:10] if doc.get("data_juntada") else ""
        conteudo = doc.get("conteudo") or ""

        parte = f"## {nome}\n**Tipo:** {tipo} | **Data:** {data}\n\n{conteudo}\n"

        if chars + len(parte) > max_chars:
            break

        partes.append(parte)
        chars += len(parte)

    return "\n---\n\n".join(partes)


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

    @mcp.tool
    async def listar_documentos(
        numero_processo: str,
        limite: int = 30,
        ordenar_por: str = "data",
        incluir_preview: bool = False,
        formato: str = "completo",
        ctx: Context = None,
    ) -> dict[str, Any]:
        """
        Lista documentos de um processo com opcoes flexiveis.

        Args:
            numero_processo: Numero do processo
            limite: Maximo de documentos (default 30, max 100)
            ordenar_por: "data" (recentes primeiro), "tipo", "sequencia"
            incluir_preview: Se True, inclui preview de 500 chars
            formato: "completo" (lista), "compacto" (sem preview), "agrupado" (por tipo)

        Substitui: preview_documentos, documentos_recentes, listar_nomes_documentos

        Returns:
            Lista de documentos ou agrupamento por tipo
        """
        limite = min(limite, MAX_DOCS_LISTA)

        client = get_supabase_client()
        docs = await client.listar_documentos(
            numero_processo,
            limite=limite,
            ordenar_por=ordenar_por,
            incluir_preview=incluir_preview,
        )

        if not docs:
            return {
                "numero_processo": numero_processo,
                "total": 0,
                "documentos": [] if formato != "agrupado" else {},
            }

        # Formato agrupado por tipo
        if formato == "agrupado":
            por_tipo: dict[str, list[dict]] = {}
            for d in docs:
                tipo = d.get("tipo_nome") or "Outros"
                if tipo not in por_tipo:
                    por_tipo[tipo] = []
                item = {
                    "seq": d.get("sequencia"),
                    "nome": d.get("nome"),
                    "data": str(d.get("data_juntada"))[:10] if d.get("data_juntada") else None,
                    "chars": d.get("tamanho_texto"),
                }
                por_tipo[tipo].append(item)
            return {"numero_processo": numero_processo, "total": len(docs), "por_tipo": por_tipo}

        # Formato completo ou compacto
        resultados = []
        for d in docs:
            item = {
                "id": d.get("id"),
                "sequencia": d.get("sequencia"),
                "tipo": d.get("tipo_nome"),
                "nome": d.get("nome") or "",
                "data_juntada": d.get("data_juntada"),
                "tamanho": d.get("tamanho_texto"),
            }
            if incluir_preview and d.get("conteudo"):
                item["preview"] = d["conteudo"][:MAX_CHARS_PREVIEW]
            resultados.append(item)

        return {
            "numero_processo": numero_processo,
            "total": len(resultados),
            "documentos": resultados,
        }

    @mcp.tool
    async def ler_documento(
        document_id: str,
        resumir: bool = True,
        ctx: Context = None,
    ) -> dict[str, Any]:
        """
        Le documento e retorna conteudo (resumido por padrao).

        Args:
            document_id: ID do documento (UUID)
            resumir: Se True, resume com LLM. Se False, retorna truncado.

        Returns:
            Documento com conteudo processado
        """
        client = get_supabase_client()
        doc = await client.ler_documento(document_id)

        if not doc:
            return {
                "erro": f"Documento {document_id} nao encontrado",
                "encontrado": False,
            }

        conteudo_original = doc.get("conteudo", "")
        tamanho = len(conteudo_original)

        # Se pequeno, retorna direto
        if tamanho <= 5000:
            conteudo_final = conteudo_original
            foi_resumido = False
        elif resumir:
            # Resume com Gemini
            llm = get_llm_service()
            resposta = await llm.resumir_texto(
                texto=conteudo_original,
                max_tokens_saida=2000,
                model="gemini-flash",
            )
            conteudo_final = resposta.text
            foi_resumido = True
        else:
            # Trunca
            conteudo_final = conteudo_original[:5000] + "\n\n[... truncado ...]"
            foi_resumido = False

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

    @mcp.tool
    async def buscar_em_documentos(
        termo: str,
        numero_processo: str | None = None,
        limite: int = 10,
        com_snippet: bool = True,
        ctx: Context = None,
    ) -> dict[str, Any]:
        """
        Busca termo nos documentos.

        Args:
            termo: Termo para buscar
            numero_processo: Filtro por processo (opcional)
            limite: Quantidade (default: 10)
            com_snippet: Se True, inclui snippet de 200 chars ao redor do termo

        Returns:
            Documentos que contem o termo
        """
        limite = min(limite, MAX_DOCS_BUSCA)

        client = get_supabase_client()
        resultados = await client.buscar_em_documentos(
            termo=termo,
            numero_processo=numero_processo,
            limite=limite,
            incluir_conteudo=com_snippet,
        )

        documentos = []
        for r in resultados:
            doc = {
                "id": r.get("id"),
                "tipo": r.get("tipo_nome"),
                "nome": r.get("nome") or "",
                "processo": r.get("numero_processo"),
            }
            if com_snippet and r.get("conteudo"):
                doc["snippet"] = _extrair_snippet(r["conteudo"], termo)
            documentos.append(doc)

        return {
            "termo": termo,
            "processo": numero_processo,
            "total": len(resultados),
            "documentos": documentos,
        }

    @mcp.tool
    async def tipos_documentos(
        numero_processo: str,
        ctx: Context = None,
    ) -> dict[str, Any]:
        """
        Contagem de documentos por tipo.

        Args:
            numero_processo: Numero do processo

        Returns:
            Tipos e quantidades
        """
        client = get_supabase_client()
        tipos = await client.tipos_documentos_agregados(numero_processo)

        return {
            "numero_processo": numero_processo,
            "total": sum(tipos.values()),
            "tipos": tipos,
        }

    @mcp.tool
    async def analisar_documento(
        document_id: str,
        pergunta: str | None = None,
        ctx: Context = None,
    ) -> dict[str, Any]:
        """
        Analisa documento com LLM.

        Args:
            document_id: ID do documento
            pergunta: Pergunta especifica (opcional)

        Returns:
            Analise do documento
        """
        client = get_supabase_client()
        doc = await client.ler_documento(document_id)

        if not doc:
            return {
                "erro": f"Documento {document_id} nao encontrado",
                "sucesso": False,
            }

        conteudo = doc.get("conteudo", "")
        if not conteudo:
            return {
                "erro": "Documento sem conteudo",
                "sucesso": False,
            }

        # Monta contexto
        contexto = f"""DOCUMENTO: {doc.get("nome", "N/A")}
Tipo: {doc.get("tipo_nome") or doc.get("tipo", "N/A")}
Data: {doc.get("data_juntada", "N/A")}
Processo: {doc.get("numero_processo", "N/A")}

CONTEUDO:
{conteudo[:200000]}"""

        # Define pergunta
        if not pergunta:
            pergunta = "Faca uma analise concisa deste documento: tipo, principais pontos, pedidos/decisoes, e datas importantes."

        llm = get_llm_service()
        resposta = await llm.query(
            pergunta=pergunta,
            contexto=contexto,
            model="gemini-flash",
            max_tokens=1500,
        )

        return {
            "sucesso": True,
            "documento": doc.get("nome"),
            "tipo": doc.get("tipo_nome") or doc.get("tipo"),
            "analise": resposta.text,
        }

    @mcp.tool
    async def analisar_documentos_por_nome(
        numero_processo: str,
        nomes: list[str],
        pergunta: str = "Analise estes documentos",
        ctx: Context = None,
    ) -> dict[str, Any]:
        """
        Busca documentos pelo nome e envia para Gemini/Grok.

        Normaliza acentos automaticamente:
        - "sentenca" encontra "Sentenca.pdf"
        - "denuncia" encontra "Denncia.pdf"
        - "peticao" encontra "Petio.pdf"

        Args:
            numero_processo: Numero do processo
            nomes: Lista de nomes ou partes de nomes
            pergunta: O que analisar

        Returns:
            Resposta com documentos encontrados
        """
        client = get_supabase_client()
        llm = get_llm_service()

        docs = await client.buscar_documentos_por_nomes(numero_processo, nomes)

        if not docs:
            return {"erro": f"Nenhum doc com nomes: {nomes}", "sucesso": False}

        contexto = _montar_contexto_documentos(docs, max_chars=7_000_000)

        # Escolhe modelo pelo tamanho
        modelo = "grok-fast" if len(contexto) > 3_000_000 else "gemini-flash"

        resposta = await llm.query(
            pergunta=pergunta,
            contexto=contexto,
            model=modelo,
            max_tokens=4000,
        )

        return {
            "sucesso": True,
            "documentos": [d.get("nome") for d in docs],
            "total": len(docs),
            "modelo": modelo,
            "resposta": resposta.text,
        }

    @mcp.tool
    async def documentos_importantes(
        numero_processo: str,
        categoria: str | None = None,
        periodo_dias: int | None = None,
        min_chars: int = 500,
        ctx: Context = None,
    ) -> dict[str, Any]:
        """
        Retorna documentos mais importantes do processo com filtros inteligentes.

        Usa view otimizada que prioriza:
        1. Sentencas
        2. Acordaos
        3. Decisoes
        4. Denuncias
        5. Peticoes
        6. Contestacoes
        7. Inqueritos
        8. Laudos

        Args:
            numero_processo: Numero do processo
            categoria: "decisorio", "peticoes", "provas", "criminal" (opcional)
            periodo_dias: Apenas docs dos ultimos N dias (opcional)
            min_chars: Tamanho minimo do conteudo (default: 500)

        Returns:
            Documentos filtrados e ordenados por relevancia
        """
        from datetime import datetime, timedelta

        client = get_supabase_client()

        # Usa view otimizada
        docs = await client.buscar_documentos_relevantes(numero_processo, limite=100)

        # Filtra por categoria se especificado
        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)
            ]

        # Filtra por periodo se especificado
        if periodo_dias:
            data_limite = (datetime.now() - timedelta(days=periodo_dias)).isoformat()
            docs = [d for d in docs if (d.get("data_juntada") or "") >= data_limite]

        # Filtra por tamanho minimo
        docs = [d for d in docs if (d.get("tamanho_texto") or 0) >= min_chars]

        return {
            "numero_processo": numero_processo,
            "filtros": {
                "categoria": categoria,
                "periodo_dias": periodo_dias,
                "min_chars": min_chars,
            },
            "total": len(docs),
            "documentos": [
                {
                    "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[:30]
            ],
        }
