"""
Teste end-to-end da tool analisar contra producao.

Requer:
- Servidor rodando em https://mcp.tecjustica.com
- Processo 0000105-15.2017.8.06.0203 na base
- Variavel ANON_KEY ou uso da API key

Executar:
    uv run pytest tests/test_e2e_analisar.py -v -s --timeout=120

Marcador: @pytest.mark.e2e (pulado por padrao em CI)
"""

import json
import os
import re

import pytest
import requests

MCP_URL = "https://mcp.tecjustica.com/mcp"
SUPABASE_AUTH_URL = "https://pglghyznirxkewcmuhvp.supabase.co/auth/v1/token"
ANON_KEY = (
    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
    "eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBnbGdoeXpuaXJ4a2V3Y211aHZwIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjYzNjk4MTgsImV4cCI6MjA4MTk0NTgxOH0."
    "hac05fv66miyiRqzwBIZYSA8gjA8dcRFOJMs3wSqWpA"
)

# Processo de teste criminal (Ceara)
PROCESSO_TESTE = "0000105-15.2017.8.06.0203"

# Pergunta de validacao e criterios
PERGUNTA_INTIMACAO = (
    "Para a audiencia do dia 23 de marco de 2006, "
    "o acusado e seu advogado foram intimados para a audiencia?"
)


def _parse_sse(response_text: str) -> dict:
    """Extrai JSON do evento SSE 'data:' da resposta."""
    for line in response_text.strip().split("\n"):
        if line.startswith("data: "):
            return json.loads(line[6:])
    raise ValueError(f"Nenhum evento SSE encontrado: {response_text[:200]}")


class MCPClient:
    """Cliente MCP simplificado para testes e2e."""

    def __init__(self, token: str) -> None:
        self.token = token
        self.session_id: str | None = None
        self.headers = {
            "Content-Type": "application/json",
            "Accept": "application/json, text/event-stream",
            "Authorization": f"Bearer {token}",
        }

    def initialize(self) -> dict:
        resp = requests.post(
            MCP_URL,
            headers=self.headers,
            json={
                "jsonrpc": "2.0",
                "id": 1,
                "method": "initialize",
                "params": {
                    "protocolVersion": "2025-03-26",
                    "capabilities": {},
                    "clientInfo": {"name": "pytest-e2e", "version": "1.0"},
                },
            },
            timeout=30,
        )
        resp.raise_for_status()
        self.session_id = resp.headers.get("mcp-session-id")
        assert self.session_id, "mcp-session-id nao retornado no initialize"
        return _parse_sse(resp.text)

    def notify_initialized(self) -> None:
        resp = requests.post(
            MCP_URL,
            headers={**self.headers, "mcp-session-id": self.session_id or ""},
            json={
                "jsonrpc": "2.0",
                "method": "notifications/initialized",
                "params": {},
            },
            timeout=10,
        )
        resp.raise_for_status()

    def call_tool(self, name: str, arguments: dict | None = None, timeout: int = 120) -> dict:
        assert self.session_id, "Sessao nao inicializada"
        resp = requests.post(
            MCP_URL,
            headers={**self.headers, "mcp-session-id": self.session_id},
            json={
                "jsonrpc": "2.0",
                "id": 99,
                "method": "tools/call",
                "params": {"name": name, "arguments": arguments or {}},
            },
            timeout=timeout,
        )
        resp.raise_for_status()
        return _parse_sse(resp.text)

    def extract_tool_text(self, result: dict) -> str:
        """Extrai texto concatenado do content[] do resultado."""
        content = result.get("result", {}).get("content", [])
        return "\n".join(item.get("text", "") for item in content)

    def extract_tool_json(self, result: dict) -> dict:
        """Extrai e parseia o primeiro JSON do content[]."""
        text = self.extract_tool_text(result)
        return json.loads(text)


def _obter_token() -> str:
    """Obtem token Supabase via email/senha ou usa API key."""
    # Tentar API key primeiro (mais simples)
    api_key = os.environ.get("MCP_API_KEY")
    if api_key:
        return api_key

    # Fallback: Supabase auth
    email = os.environ.get("SUPABASE_TEST_EMAIL", "marcosmarf27@gmail.com")
    senha = os.environ.get("SUPABASE_TEST_PASSWORD", "224351*27")

    resp = requests.post(
        f"{SUPABASE_AUTH_URL}?grant_type=password",
        headers={"apikey": ANON_KEY, "Content-Type": "application/json"},
        json={"email": email, "password": senha},
        timeout=15,
    )
    resp.raise_for_status()
    return resp.json()["access_token"]


@pytest.fixture(scope="module")
def mcp_client() -> MCPClient:
    """Cria e inicializa cliente MCP para toda a suite."""
    token = _obter_token()
    client = MCPClient(token)
    client.initialize()
    client.notify_initialized()
    return client


# ============================================================
# Testes
# ============================================================


@pytest.mark.e2e
def test_analisar_intimacao_audiencia(mcp_client: MCPClient) -> None:
    """
    CASO DE TESTE: Intimacao para audiencia de 23/03/2006.

    Processo: 0000105-15.2017.8.06.0203 (criminal, Ceara)
    Pergunta: O acusado e seu advogado foram intimados para a audiencia?
    Validacao: A resposta deve confirmar que SIM, foram intimados.
    """
    result = mcp_client.call_tool(
        "analisar",
        {
            "numero_processo": PROCESSO_TESTE,
            "pergunta": PERGUNTA_INTIMACAO,
        },
        timeout=180,  # map-reduce pode demorar
    )

    data = mcp_client.extract_tool_json(result)

    # Validacoes estruturais
    assert data.get("sucesso") is True, f"Tool falhou: {data}"
    assert data.get("numero_processo") == PROCESSO_TESTE
    assert data.get("modelo") == "gemini-flash"
    assert "resposta" in data, "Campo 'resposta' ausente"

    resposta = data["resposta"].lower()

    # Validacao semantica: a resposta deve confirmar intimacao
    # Aceita variantes: "sim", "foram intimados", "houve intimacao", "intimado(s)", etc.
    padroes_positivos = [
        r"sim",
        r"foram?\s+intimad[oa]s?",
        r"intimad[oa]s?\s+para\s+a\s+audi[eê]ncia",
        r"houve\s+intima[cç][aã]o",
        r"devidamente\s+intimad",
        r"intima[cç][aã]o.*realizada",
    ]

    encontrou = any(re.search(p, resposta) for p in padroes_positivos)
    assert encontrou, (
        f"Resposta NAO confirma intimacao do acusado/advogado.\n"
        f"Estrategia: {data.get('estrategia')}\n"
        f"Resposta (primeiros 500 chars): {data['resposta'][:500]}"
    )

    # Log informativo
    print("\n--- Resultado do teste ---")
    print(f"Estrategia: {data.get('estrategia')}")
    print(f"Lotes: {data.get('lotes', 'N/A')}")
    print(f"Docs: {data.get('docs_total', 'N/A')}")
    print(f"Resposta (resumo): {data['resposta'][:300]}...")


PERGUNTA_INTIMACAO_TISO = (
    "Para a audiencia do dia 12 de marco de 2026, "
    "o acusado e seu advogado foram intimados para a audiencia da TISO "
    "(transacao integral de solucao oral)?"
)


@pytest.mark.e2e
def test_analisar_intimacao_audiencia_tiso(mcp_client: MCPClient) -> None:
    """
    CASO DE TESTE: Intimacao para audiencia TISO de 12/03/2026.

    Processo: 0000105-15.2017.8.06.0203 (criminal, Ceara)
    Pergunta: O acusado e advogado foram intimados para TISO em 12/03/2026?
    Validacao: A resposta deve confirmar que SIM, foram intimados.
    """
    result = mcp_client.call_tool(
        "analisar",
        {
            "numero_processo": PROCESSO_TESTE,
            "pergunta": PERGUNTA_INTIMACAO_TISO,
        },
        timeout=300,
    )

    data = mcp_client.extract_tool_json(result)

    # Validacoes estruturais
    assert data.get("sucesso") is True, f"Tool falhou: {data}"
    assert data.get("numero_processo") == PROCESSO_TESTE
    assert data.get("modelo") == "gemini-flash"
    assert "resposta" in data, "Campo 'resposta' ausente"

    resposta = data["resposta"].lower()

    # Validacao semantica: a resposta deve confirmar intimacao
    # Padroes simples para evitar problemas com encoding de acentos
    padroes_positivos = [
        r"foi\s+intimad",
        r"foram?\s+intimad",
        r"intimad[oa]s?\s+para",
        r"devidamente\s+intimad",
        r"confirmou\s+o\s+recebimento",
    ]

    encontrou = any(re.search(p, resposta) for p in padroes_positivos)
    assert encontrou, (
        f"Resposta NAO confirma intimacao do acusado/advogado para TISO.\n"
        f"Estrategia: {data.get('estrategia')}\n"
        f"Resposta (primeiros 500 chars): {data['resposta'][:500]}"
    )

    # Log informativo
    print("\n--- Resultado do teste TISO ---")
    print(f"Estrategia: {data.get('estrategia')}")
    print(f"Lotes: {data.get('lotes', 'N/A')}")
    print(f"Docs: {data.get('docs_total', 'N/A')}")
    print(f"Resposta (resumo): {data['resposta'][:300]}...")


@pytest.mark.e2e
def test_analisar_retorna_metadata(mcp_client: MCPClient) -> None:
    """Verifica que analisar retorna metadata do map-reduce."""
    result = mcp_client.call_tool(
        "analisar",
        {
            "numero_processo": PROCESSO_TESTE,
            "pergunta": "Qual a situacao atual do processo?",
        },
        timeout=180,
    )

    data = mcp_client.extract_tool_json(result)

    assert data.get("sucesso") is True
    assert data.get("estrategia") in ("contexto_unico", "map_reduce")
    assert "docs_total" in data
    assert data["docs_total"] > 0
