from __future__ import annotations

import json
from pathlib import Path

import pytest
import yaml

from app.domain.contas.service import ContasDomainService
from app.domain.contas.workflow_actions import build_contas_workflow_actions
from contas_mcp.servers.contas_mcp_server import main as mcp

ROOT = Path(__file__).resolve().parents[2]
REQUESTED = {
    "consultar_faturas", "consultar_plano", "invoice_explanation", "buscar_informacao",
    "consultar_vas", "consultar_historico_vas", "cancelar_vas_avulso",
    "tratar_vas_estrategico", "validar_contestacao", "contestar_cobranca",
    "finalizar_atendimento", "consultar_status_solicitacao", "enviar_sms",
    "recuperar_fatura_pdf", "pro_rata", "termino_desconto", "valor_divergente",
    "retomar_workflow",
}


def test_todas_as_capabilities_solicitadas_estao_expostas_no_mcp():
    assert REQUESTED <= set(mcp.TOOLS)


def test_todas_as_capabilities_solicitadas_estao_habilitadas_no_registry():
    cfg = yaml.safe_load((ROOT / "config/tools.yaml").read_text(encoding="utf-8"))["tools"]
    assert REQUESTED <= set(cfg)
    assert all(cfg[name].get("enabled", True) for name in REQUESTED)


def test_buscar_informacao_preserva_tool_original_mas_delega_rag_ao_framework():
    out = ContasDomainService().buscar_informacao(
        queries=["Aya Audiobooks Premium o que é", "Food Balance o que é"]
    )
    assert out["requires_rag"] is True
    assert out["source"] == "agent_framework.rag"
    assert out["rag_queries"] == ["Aya Audiobooks Premium o que é", "Food Balance o que é"]


def test_consultar_plano_extrai_planos_da_evidencia_sem_llm():
    billing = json.loads((ROOT / "app/domain/contas/fixtures/divergencia.json").read_text(encoding="utf-8"))
    out = ContasDomainService().consultar_plano(msisdn="119", billing_analysis=billing)
    assert out["count"] == 2
    assert {p["name"] for p in out["plans"]} == {"TIM Black A 8.0", "TIM CTRL Redes Sociais 8.0"}


def test_invoice_explanation_preserva_detail_e_resumo_semantico_para_composicao():
    svc = ContasDomainService()
    detail = {"parsed_content": {"total_geral": 197.43}}
    out = svc.invoice_explanation(
        msisdn="119",
        complete_invoices_payload={"paymentItems": []},
        billing_analysis={"invoiceExplanation": "Base"},
        invoice_detail=detail,
        invoice_amount="197.43",
        invoice_period="14/10 a 13/11",
    )
    assert out["invoice_detail"] == detail
    assert out["invoice_amount"] == "197.43"
    assert out["invoice_period"] == "14/10 a 13/11"


def test_invoice_explanation_restaura_composicao_llm_no_framework():
    reg = build_contas_workflow_actions(ContasDomainService())
    out = reg.get("formatar_invoice_explanation")(
        {"explicacao_base": "TIM Fashion R$ 10,00", "invoice_detail": {}}, {"input": {}}
    )
    assert out["await_user_input"] is True
    assert out["requires_llm_composition"] is True
    assert "não invente" in out["response_instruction"]
    assert "Com essa explicação, sanei sua dúvida?" in out["mensagem"]


def test_pro_rata_deriva_exatamente_dois_planos_do_pdf_sem_llm():
    detail = json.loads((ROOT / "app/domain/contas/fixtures/invoice_pdf_include_danfe_true.json").read_text(encoding="utf-8"))
    args = {"msisdn": "11999999999", "invoice_detail": detail}
    plans = mcp._derive_pro_rata_plans(args)
    assert len(plans) == 2
    assert {p["desc"] for p in plans} == {"TIM Black A 8.0", "TIM CTRL Redes Sociais 8.0"}
    assert mcp._prepare_pro_rata(args) is None
    assert args["has_plano_controle"] is True


def test_pro_rata_falha_fechado_sem_exatamente_dois_planos():
    args = {"msisdn": "119", "planos": [{"desc": "Plano único"}]}
    out = mcp._prepare_pro_rata(args)
    assert out["success"] is False
    assert out["reason"] == "requires_exactly_two_plans"
    assert out["plans_found"] == 1


@pytest.mark.asyncio
async def test_validar_contestacao_usa_mesma_cval_e_rejeita_valor_acima_da_fatura(monkeypatch):
    billing = json.loads((ROOT / "app/domain/contas/fixtures/divergencia.json").read_text(encoding="utf-8"))

    async def no_enrich(name, args):
        return None

    monkeypatch.setattr(mcp, "_enrich_invoice_context", no_enrich)
    out = await mcp._validate_contestation({
        "msisdn": "11999999999",
        "subject": "TIM Fashion Mensal",
        "valor": 150,
        "motivo": "quero contestar TIM Fashion Mensal",
        "billing_analysis": billing,
    })
    assert out["eligible"] is False
    assert out["reason"] == "CVAL"
    assert out["validation_log"][0]["erro"] == "valor_ajuste_maior_que_item"


@pytest.mark.asyncio
async def test_validar_contestacao_rejeita_valor_que_nao_pertence_ao_item(monkeypatch):
    billing = json.loads((ROOT / "app/domain/contas/fixtures/divergencia.json").read_text(encoding="utf-8"))

    async def no_enrich(name, args):
        return None

    monkeypatch.setattr(mcp, "_enrich_invoice_context", no_enrich)
    out = await mcp._validate_contestation({
        "msisdn": "11999999999",
        "subject": "TIM Fashion Mensal",
        "valor": 50,
        "motivo": "quero contestar TIM Fashion Mensal",
        "billing_analysis": billing,
    })
    assert out["eligible"] is False
    assert out["status"] == "NEEDS_PARAMETER"
    assert out["parameter"] == "valor"
    assert out["candidate_value"] == 50
    assert out["billed_value"] == "10"
    assert out["resolved_value"] is None


def test_termino_desconto_e_valor_divergente_preservam_semantica_do_original():
    reg = build_contas_workflow_actions(ContasDomainService())
    action = reg.get("formatar_capability_resposta")
    end = action({"tipo": "termino_desconto", "nome_plano": "TIM Black", "msisdn": "11999999999"}, {"input": {}})
    div = action({"tipo": "valor_divergente", "msisdn": "11999999999"}, {"input": {}})
    assert "desconto de fidelidade do plano TIM Black" in end["mensagem"]
    assert "período promocional contratado expirou" in end["mensagem"]
    assert "alteração no valor do plano" in div["mensagem"]
    assert "final 99" in div["mensagem"]


def test_status_solicitacao_nao_confunde_message_id_com_protocolo():
    mapping = yaml.safe_load((ROOT / "config/mcp_parameter_mapping.yaml").read_text(encoding="utf-8"))["mcp_parameter_mapping"]["tools"]["consultar_status_solicitacao"]
    assert "interaction_key" not in mapping.get("map", {})
    assert "protocol" in mapping.get("extract", {})


def test_finalizacao_preserva_status_explicito_do_contrato_original():
    cfg = yaml.safe_load((ROOT / "config/tools.yaml").read_text(encoding="utf-8"))["tools"]["finalizar_atendimento"]
    assert "status" in cfg.get("requires", [])
    mapping = yaml.safe_load((ROOT / "config/mcp_parameter_mapping.yaml").read_text(encoding="utf-8"))["mcp_parameter_mapping"]["tools"]["finalizar_atendimento"]
    assert "status" in mapping.get("extract", {})


class _DirectClient:
    def consultar_vas(self, msisdn): return {"products": [{"name": "VAS"}]}
    def historico_vas(self, msisdn): return {"services": [{"name": "OLD"}]}
    def status_sr(self, payload): return {"protocolNumber": payload.get("protocolNumber"), "status": "Fechado"}
    def sms(self, msisdn, message): return {"sent": True, "msisdn": msisdn, "message": message}
    def secure_pdf(self, msisdn, invoice_id, customer_id=""): return {"invoiceId": invoice_id, "url": "secure"}


def test_tools_diretas_vas_historico_status_sms_pdf_mantem_contratos_de_dominio():
    svc = ContasDomainService(client=_DirectClient())  # type: ignore[arg-type]
    assert svc.consultar_vas(msisdn="119")["products"][0]["name"] == "VAS"
    assert svc.consultar_historico_vas(msisdn="119")["services"][0]["name"] == "OLD"
    assert svc.consultar_status_solicitacao(msisdn="119", protocol="P1")["protocolNumber"] == "P1"
    assert svc.enviar_sms(msisdn="119", message="ok")["sent"] is True
    assert svc.recuperar_fatura_pdf(msisdn="119", invoice_id="I1")["invoiceId"] == "I1"
