from __future__ import annotations

import pytest

from agent_framework.guardrails.framework_llm_client import classify_with_framework_llm
from agent_framework.guardrails.calibrated.llm_client import _BINARY_BLOCK_DIGIT, _BINARY_TASKS
from agent_framework.guardrails.calibrated.prompts.pinj import build_pinj_prompt
from agent_framework.guardrails.calibrated.prompts.revprec import build_revprec_prompt


class FakeLLM:
    def __init__(self, content: str):
        self.content = content
        self.profile_resolver = None

    async def ainvoke(self, messages, **kwargs):
        return self.content


@pytest.mark.asyncio
@pytest.mark.parametrize(
    ("task", "content", "allowed"),
    [
        ("PINJ", "1", True),
        ("PINJ", "0", False),
        ("PINJ", "prosa 1 e veredito 0", False),
        ("PINJ", "sem digito", True),
        ("PINJ", "", True),
        ("REVPREC", "1", False),
        ("REVPREC", "0", True),
        ("REVPREC", "Resposta: 1", False),
        ("REVPREC", "não sei", True),
        ("REVPREC", "", True),
    ],
)
async def test_binary_guardrail_semantics(task: str, content: str, allowed: bool, monkeypatch):
    monkeypatch.setenv("USE_MOCK_LLM", "false")
    out = await classify_with_framework_llm(
        FakeLLM(content), task, {"text": "texto", "context": {}}, profile_name="guardrail"
    )
    assert bool(out["allowed"]) is allowed


def test_binary_polarity_contract():
    assert _BINARY_BLOCK_DIGIT["REVPREC"] == "1"
    assert _BINARY_BLOCK_DIGIT.get("PINJ", "0") == "0"
    assert "PINJ" in _BINARY_TASKS and "REVPREC" in _BINARY_TASKS


def test_pinj_prompt_is_binary_and_keeps_examples():
    prompt = build_pinj_prompt("texto qualquer")
    assert "Responda APENAS um caractere" in prompt
    assert '"allowed"' not in prompt
    assert prompt.count("  Texto: ") == 17
    assert prompt.count("  Saída: 0") == 11
    assert prompt.count("  Saída: 1") == 6


def test_revprec_prompt_preserves_boundaries():
    prompt = build_revprec_prompt("FALA_NOVA", "\nHistorico da conversa:\n[assistant] CANCELEI_ANTES\n")
    assert "APENAS 1 ou 0" in prompt
    assert 'somente a fala do bloco "Resposta:"' in prompt
    assert "PROTOCOLO" in prompt
    assert "DESCRIÇÃO DA FATURA" in prompt
