from app.domain.contas import ContasDomainService


def test_read_only_integrations_with_fixtures(monkeypatch):
    monkeypatch.setenv("TIM_USE_MOCK_GATEWAY", "true")
    svc = ContasDomainService()
    assert svc.consultar_faturas(msisdn="11999999999").get("paymentItems")
    assert svc.consultar_vas(msisdn="11999999999").get("products")
    assert svc.consultar_historico_vas(msisdn="11999999999").get("services")


def test_cancel_vas_is_domain_operation_not_conversation_engine(monkeypatch):
    monkeypatch.setenv("TIM_USE_MOCK_GATEWAY", "true")
    svc = ContasDomainService()
    out = svc.cancelar_vas_avulso(msisdn="11999999999", subject="TIM Fashion Mensal")
    assert out["success"] is True
    assert out["block"]["status"] == 200
    assert out["cancellation"]["status"] == 200


def test_contestation_mock(monkeypatch):
    monkeypatch.setenv("TIM_USE_MOCK_GATEWAY", "true")
    svc = ContasDomainService()
    out = svc.contestar_cobranca(msisdn="11999999999", subject="Tamboro Mensal", valor=14.99, motivo="não reconheço")
    assert out["success"] is True
    assert out["protocol"]
    assert out["contestation"]


def test_cancelamento_usa_historico_como_fallback_quando_ativo_nao_encontra():
    from app.domain.contas.service import ContasDomainService

    class Client:
        def __init__(self):
            self.blocked = []
            self.cancelled = []
        def consultar_vas(self, msisdn):
            return {"products": []}
        def historico_vas(self, msisdn):
            return {"services": [{"name": "Max mensal fatura", "appId": 14395, "cspId": 825, "canCancel": True}]}
        def bloquear_vas(self, msisdn, service):
            self.blocked.append((msisdn, service))
            return {"ok": True}
        def cancelar_vas(self, msisdn, service, protocol=""):
            self.cancelled.append((msisdn, service, protocol))
            return {"ok": True}

    client = Client()
    result = ContasDomainService(client=client).cancelar_vas_avulso(
        msisdn="11999999999", subject="Max mensal fatura", protocol="PRT-1"
    )
    assert result["success"] is True
    assert result["evidence_source"] == "history"
    assert client.blocked[0][1]["appId"] == 14395
    assert client.cancelled[0][2] == "PRT-1"


def test_cancelamento_nao_recancela_servico_inativo_do_historico():
    from app.domain.contas.service import ContasDomainService

    class Client:
        def consultar_vas(self, msisdn):
            return {"products": []}
        def historico_vas(self, msisdn):
            return {"services": [{"name": "Max mensal fatura", "appId": 14395, "cspId": 825, "canCancel": False}]}
        def bloquear_vas(self, *args, **kwargs):
            raise AssertionError("não deve bloquear")
        def cancelar_vas(self, *args, **kwargs):
            raise AssertionError("não deve cancelar")

    result = ContasDomainService(client=Client()).cancelar_vas_avulso(
        msisdn="11999999999", subject="Max mensal fatura"
    )
    assert result["success"] is False
    assert result["reason"] == "already_inactive_or_blocked"


def test_finalizacao_normaliza_status_invalido_e_summary():
    from app.domain.contas.service import ContasDomainService

    class Client: pass
    result = ContasDomainService(client=Client()).finalizar_atendimento(
        status="qualquer_coisa", summary=""
    )
    assert result["status"] == "erro_falha_sistema"
    assert result["summary"] == "Encerramento realizado pelo agente."


def test_finalizacao_preserva_status_valido_e_prefixa_summary():
    from app.domain.contas.service import ContasDomainService

    class Client: pass
    result = ContasDomainService(client=Client()).finalizar_atendimento(
        status="resolvido_outros_assuntos",
        summary="VAS cancelado e cliente quer falar de plano.",
    )
    assert result["status"] == "resolvido_outros_assuntos"
    assert result["summary"] == (
        "Encerramento realizado pelo agente. VAS cancelado e cliente quer falar de plano."
    )


def test_finalizacao_informacional_cria_protocolo_fechado_sem_duplicar_status():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions

    class Client:
        def __init__(self): self.protocol_calls = []; self.status_calls = []
        def abrir_protocolo(self, payload):
            self.protocol_calls.append(payload)
            return {"protocolNumber": "INFO-123"}
        def status_sr(self, payload):
            self.status_calls.append(payload)
            return {"ok": True}

    from app.domain.contas.service import ContasDomainService
    client = Client()
    reg = build_contas_workflow_actions(ContasDomainService(client=client))
    action = reg.get("finalizar_atendimento_action")
    result = action({
        "status": "resolvido",
        "summary": "Explicação aceita.",
        "msisdn": "11999999999",
        "social_sec_no": "12345678901",
        "informational_vas_types": ["bundle", "estrategico"],
    }, {"input": {}})
    assert result["protocol_number"] == "INFO-123"
    assert result["informational_protocol_notes"] == "Explicação de VAS Bundle, VAS Estratégico"
    assert client.protocol_calls[0]["requestStatus"] == "Fechado"
    assert client.protocol_calls[0]["status"] == "CLOSED"
    assert client.protocol_calls[0]["serviceRequestNotes"] == "Explicação de VAS Bundle, VAS Estratégico"
    assert client.status_calls == []


def test_finalizacao_com_protocolo_existente_nao_cria_informacional():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    from app.domain.contas.service import ContasDomainService

    class Client:
        def __init__(self): self.protocol_calls = []; self.status_calls = []
        def abrir_protocolo(self, payload):
            self.protocol_calls.append(payload)
            return {"protocolNumber": "NOVO"}
        def status_sr(self, payload):
            self.status_calls.append(payload)
            return {"ok": True}

    client = Client()
    action = build_contas_workflow_actions(ContasDomainService(client=client)).get("finalizar_atendimento_action")
    result = action({
        "status": "resolvido",
        "summary": "ok",
        "msisdn": "11999999999",
        "protocol_number": "PRT-EXISTENTE",
        "informational_vas_types": ["avulso"],
    }, {"input": {}})
    assert client.protocol_calls == []
    assert client.status_calls[0]["protocolNumber"] == "PRT-EXISTENTE"
    assert "informational_protocol_notes" not in result


import pytest


@pytest.mark.parametrize(
    ("types", "expected"),
    [
        ({"bundle"}, "Explicação de VAS Bundle"),
        ({"estrategico"}, "Explicação de VAS Estratégico"),
        ({"avulso"}, "Explicação de VAS Avulso"),
        ({"bundle", "estrategico"}, "Explicação de VAS Bundle, VAS Estratégico"),
        ({"bundle", "avulso"}, "Explicação de VAS Bundle, VAS Avulso"),
        ({"estrategico", "avulso"}, "Explicação de VAS Estratégico, VAS Avulso"),
        ({"bundle", "estrategico", "avulso"}, "Explicação de VAS Bundle, VAS Estratégico, VAS Avulso"),
    ],
)
def test_finalizacao_informacional_notas_canonicas(types, expected):
    from app.domain.contas.workflow_actions import _format_informational_vas_notes

    assert _format_informational_vas_notes(types) == expected


def test_finalizacao_cria_protocolo_informacional_quando_invoice_explanation_executou():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions

    class Client:
        def __init__(self):
            self.protocol_calls = []
        def abrir_protocolo(self, payload):
            self.protocol_calls.append(payload)
            return {"interactionProtocol": "INFO-123"}
        def status_sr(self, payload):
            raise AssertionError("protocolo informacional fechado nao deve ser fechado novamente")
    class Service:
        def __init__(self): self.client = Client()
        def finalizar_atendimento(self, *, status, summary, protocol="", msisdn="", **kwargs):
            return {"success": True, "status": status, "summary": summary}

    service = Service()
    reg = build_contas_workflow_actions(service)  # type: ignore[arg-type]
    action = reg.get("finalizar_atendimento_action")
    result = action({
        "status": "resolvido",
        "summary": "Cliente entendeu a explicação.",
        "msisdn": "11999999999",
        "social_sec_no": "12345678901",
        "message_id": "msg-123",
        "invoice_explanation_base": "Explicação dos valores da fatura.",
        "business_workflows_executed": ["invoice_explanation"],
    }, {"input": {}})
    assert result["protocol_number"] == "INFO-123"
    assert service.client.protocol_calls[0]["serviceRequestNotes"] == "Explicação dos valores da fatura"


def test_finalizacao_nao_cria_protocolo_apenas_por_prefetch_invoice_explanation():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class Client:
        def __init__(self): self.protocol_calls = []
        def abrir_protocolo(self, payload): self.protocol_calls.append(payload); return {"interactionProtocol": "BAD"}
    class Service:
        def __init__(self): self.client = Client()
        def finalizar_atendimento(self, *, status, summary, protocol="", msisdn="", **kwargs): return {"success": True}
    service = Service()
    action = build_contas_workflow_actions(service).get("finalizar_atendimento_action")  # type: ignore[arg-type]
    result = action({"status": "resolvido", "msisdn": "119", "invoice_explanation_base": "prefetch"}, {"input": {}})
    assert "protocol_number" not in result
    assert service.client.protocol_calls == []


def test_finalizacao_nao_duplica_protocolo_quando_contestacao_ja_existe():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class Client:
        def __init__(self): self.protocol_calls = []; self.status_calls=[]
        def abrir_protocolo(self, payload): self.protocol_calls.append(payload); return {"interactionProtocol": "BAD"}
        def status_sr(self, payload): self.status_calls.append(payload); return {"ok": True}
    class Service:
        def __init__(self): self.client = Client()
        def finalizar_atendimento(self, *, status, summary, protocol="", msisdn="", **kwargs):
            if protocol: self.client.status_sr({"protocolNumber": protocol, "status": "Fechado"})
            return {"success": True}
    service = Service()
    action = build_contas_workflow_actions(service).get("finalizar_atendimento_action")  # type: ignore[arg-type]
    result = action({
        "status": "resolvido", "msisdn": "119", "informational_vas_types": ["avulso"],
        "contestacao_protocol": "2026000083899",
    }, {"input": {}})
    assert "protocol_number" not in result
    assert service.client.protocol_calls == []


def test_finalizacao_reusa_protocolo_veb_ja_fechado_sem_abrir_outro():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class Client:
        def __init__(self): self.protocol_calls=[]; self.status_calls=[]
        def abrir_protocolo(self, payload): self.protocol_calls.append(payload); return {"interactionProtocol":"BAD"}
        def status_sr(self, payload): self.status_calls.append(payload); return {"ok":True}
    class Service:
        def __init__(self): self.client=Client()
        def finalizar_atendimento(self, *, status, summary, protocol="", msisdn="", **kwargs):
            if protocol: self.client.status_sr({"protocolNumber":protocol})
            return {"success":True}
    svc=Service(); action=build_contas_workflow_actions(svc).get("finalizar_atendimento_action")  # type: ignore[arg-type]
    result=action({
        "status":"resolvido", "msisdn":"119", "protocol_closed":True,
        "protocolos_por_linha":[{"msisdn":"119","protocolo_id":"VEB-123"}],
        "informational_vas_types":["estrategico"],
    }, {"input":{}})
    assert result["protocol_number"] == "VEB-123"
    assert svc.client.protocol_calls == []
    assert svc.client.status_calls == []


def test_finalizacao_force_rt15_cria_novo_protocolo_mesmo_com_veb_fechado():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class Client:
        def __init__(self): self.protocol_calls=[]
        def abrir_protocolo(self,payload): self.protocol_calls.append(payload); return {"interactionProtocol":"INFO-RT15"}
    class Service:
        def __init__(self): self.client=Client()
        def finalizar_atendimento(self, **kwargs): return {"success":True}
    svc=Service(); action=build_contas_workflow_actions(svc).get("finalizar_atendimento_action")  # type: ignore[arg-type]
    result=action({
        "status":"resolvido", "msisdn":"119", "protocol_closed":True,
        "protocolos_por_linha":[{"protocolo_id":"VEB-123"}],
        "informational_vas_types":["bundle"], "force_rt15_finalization_protocol":True,
    }, {"input":{}})
    assert result["protocol_number"] == "INFO-RT15"
    assert len(svc.client.protocol_calls) == 1
    assert svc.client.protocol_calls[0]["serviceRequestNotes"].endswith("VAS Bundle")


def test_finalizacao_veb_deferido_suprime_evento_cvn_de_protocolo():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class Client:
        def abrir_protocolo(self,payload): return {"interactionProtocol":"VEB-NEW"}
    class Service:
        def __init__(self): self.client=Client()
        def finalizar_atendimento(self, **kwargs): return {"success":True}
    action=build_contas_workflow_actions(Service()).get("finalizar_atendimento_action")  # type: ignore[arg-type]
    result=action({
        "status":"resolvido", "msisdn":"119", "informational_vas_types":["estrategico"],
        "vas_estrategico_protocol_deferred_to_finalization":True, "suppress_cvn_protocol_ic":True,
    }, {"input":{}})
    codes=[e.get("code") if isinstance(e,dict) else str(e) for e in result["business_events"]]
    assert result["protocol_number"] == "VEB-NEW"
    assert "CVN.010" not in codes and "CVN.011" not in codes


def test_invoice_explanation_converte_retry_transport_em_rct_por_tentativa():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class Client: pass
    class Service:
        client = Client()
        def invoice_explanation(self, *, msisdn, **params):
            return {"billing_analysis": {
                "invoiceExplanation": "Sua fatura mudou por um serviço adicional.",
                "_transport": {"rct_operation": "base_conhecimento", "attempts": [
                    {"attempt": 1, "success": False, "status_code": 500, "latency_ms": 12},
                    {"attempt": 2, "success": True, "status_code": 200, "latency_ms": 7},
                ]},
            }}
    action=build_contas_workflow_actions(Service()).get("preparar_invoice_explanation")  # type: ignore[arg-type]
    result=action({"msisdn":"119"}, {"input":{"msisdn":"119"}})
    codes=[e.get("code") for e in result["business_events"] if isinstance(e,dict)]
    assert "RCT.080" in codes
    assert "RCT.081" in codes
    assert result["success"] is True


def test_invoice_explanation_falha_preserva_rct_das_tres_tentativas():
    from app.domain.contas.client import TimApiError
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class Client: pass
    class Service:
        client=Client()
        def invoice_explanation(self, *, msisdn, **params):
            raise TimApiError("gateway indisponivel", status_code=550, body={"message":"erro"}, attempts=[
                {"attempt":1,"success":False,"status_code":500,"latency_ms":3},
                {"attempt":2,"success":False,"status_code":502,"latency_ms":4},
                {"attempt":3,"success":False,"status_code":550,"latency_ms":5},
            ])
    action=build_contas_workflow_actions(Service()).get("preparar_invoice_explanation")  # type: ignore[arg-type]
    result=action({"msisdn":"119"}, {"input":{"msisdn":"119"}})
    codes=[e.get("code") for e in result["business_events"] if isinstance(e,dict)]
    assert [c for c in codes if str(c).startswith("RCT.")] == ["RCT.080","RCT.082","RCT.084"]
    assert result["api_status_code"] == 550
    assert result["service_failed"] is True


def _event_codes(value):
    return [x.get("code") if isinstance(x, dict) else str(x) for x in (value.get("business_events") or [])]


def test_cancelamento_batch_emite_vaa_caminho_feliz_uma_vez():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class Client:
        def consultar_vas(self, msisdn):
            return {"services": [{"bill_description": "TIM Fashion Mensal", "app_id": "A1", "can": {"cancel": True}}]}
        def line_info(self, msisdn): return {"socialSecNo": "123"}
        def abrir_protocolo(self, payload): return {"protocol": "P-1"}
    class Service:
        client = Client()
        def cancelar_vas_avulso(self, **kwargs):
            return {"success": True, "msisdn": kwargs["msisdn"], "subject": kwargs["subject"], "protocol": kwargs.get("protocol", "")}
    from agent_framework.idempotency import InMemoryIdempotencyStore
    action = build_contas_workflow_actions(Service(), idempotency_store=InMemoryIdempotencyStore()).get("cancelamento_vas_avulso_batch")  # type: ignore[arg-type]
    import asyncio
    result = asyncio.run(action({"msisdn": "5511999999999", "items": [{"msisdn": "5511999999999", "service": "TIM Fashion Mensal"}]}, {"input": {}}))
    codes = _event_codes(result)
    assert codes.count("VAA.001") == 1
    assert codes.count("VAA.002") == 1
    assert codes.count("VAA.003") == 1
    assert "VAA.004" not in codes
    vaa = [x for x in result["business_events"] if isinstance(x, dict) and str(x.get("code", "")).startswith("VAA.")]
    assert all(x["payload"]["gsm"] == "5511999999999" for x in vaa)


def test_cancelamento_batch_emite_vaa004_quando_falha_operacional():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class Service:
        class Client:
            def line_info(self, msisdn): return {"socialSecNo": "123"}
            def abrir_protocolo(self, payload): return {"protocol": "P-1"}
        client = Client()
        def cancelar_vas_avulso(self, **kwargs):
            return {"success": False, "msisdn": kwargs["msisdn"], "subject": kwargs["subject"], "reason": "block_vas_failed", "error": "timeout"}
    from agent_framework.idempotency import InMemoryIdempotencyStore
    action = build_contas_workflow_actions(Service(), idempotency_store=InMemoryIdempotencyStore()).get("cancelamento_vas_avulso_batch")  # type: ignore[arg-type]
    import asyncio
    result = asyncio.run(action({"msisdn": "5511999999999", "items": [{"msisdn": "5511999999999", "service": "TIM Fashion Mensal"}]}, {"input": {}}))
    codes = _event_codes(result)
    assert "VAA.001" in codes and "VAA.002" in codes and "VAA.004" in codes
    assert "VAA.003" not in codes
