from __future__ import annotations

import pytest


def _result(name: str, status: str, output: dict, *, error: str | None = None):
    return {
        "execution_id": f"exec-{name}",
        "workflow_name": name,
        "workflow_version": 1,
        "status": status,
        "output": output,
        "state": {},
        "trace": [],
        "error": error,
        "error_details": None,
    }


class _Service:
    def consultar_faturas(self, *, msisdn: str):
        return {
            "billingProfile": {"customer": {"document": "12345678901", "customerId": "344575482"}},
            "paymentItems": [{"invoiceId": "5536806781", "dueDate": "2025-08-11"}],
        }


@pytest.mark.asyncio
async def test_success_implicito_por_cancelados_sem_flag_success(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.i = 0
        async def arun(self, name, payload, execution_id=None):
            self.i += 1
            if self.i == 1:
                return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
                    "cancelados": [{"msisdn": payload["msisdn"], "servico": "Tamboro Mensal", "valor": "14,99"}],
                    "itens_para_contestacao": [{"msisdn": payload["msisdn"], "subject": "Tamboro Mensal"}],
                }})
            return _result(name, "COMPLETED", {
                "registrar_protocolo": {"protocolo_id": "PRT-D2EFF9B40B", "protocol_closed": True},
                "abrir_contestacao_cliente": {"success": True, "contested_items": [{"itemName": "Tamboro Mensal", "status": "INICIADA"}]},
            })

    runtime = Runtime()
    monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
    monkeypatch.setattr(main, "service", _Service())
    result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "Tamboro Mensal", "valor": "14,99"})
    assert result["success"] is True
    assert result["protocol_closed"] is True
    assert result["contestacao_protocol"] == "PRT-D2EFF9B40B"


@pytest.mark.asyncio
async def test_lista_explicita_vazia_de_candidatos_nao_faz_fallback_para_cancelados(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.calls = []
        async def arun(self, name, payload, execution_id=None):
            self.calls.append(name)
            return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
                "cancelados": [{"msisdn": payload["msisdn"], "servico": "TIM Fashion Mensal"}],
                "contestation_candidates": [],
            }})

    runtime = Runtime()
    monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
    result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "TIM Fashion Mensal", "valor": "14,99"})
    assert runtime.calls == ["cancelamento_vas_avulso"]
    assert result["success"] is True
    assert "contestacao_workflow" not in result


@pytest.mark.asyncio
async def test_no_match_nao_contesta_valor_nem_chama_contestacao(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.calls = []
        async def arun(self, name, payload, execution_id=None):
            self.calls.append(name)
            return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
                "results": [{"success": False, "subject": "Inexistente", "error": "serviço não encontrado", "reason": "service_not_found"}],
                "contestation_candidates": [],
                "nao_encontrados": [{"servico": "Inexistente"}],
            }})

    runtime = Runtime()
    monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
    result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "Inexistente", "valor": "99,99"})
    assert runtime.calls == ["cancelamento_vas_avulso"]
    assert result["success"] is False
    assert "contestacao_workflow" not in result
    assert "99,99" not in result["mensagem"]


@pytest.mark.asyncio
async def test_protocol_closed_da_contestacao_e_preservado(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.i = 0
        async def arun(self, name, payload, execution_id=None):
            self.i += 1
            if self.i == 1:
                return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
                    "results": [{"success": True, "subject": "TIM Fashion Mensal", "msisdn": payload["msisdn"]}],
                    "contestation_candidates": [{"success": True, "subject": "TIM Fashion Mensal", "msisdn": payload["msisdn"]}],
                }})
            return _result(name, "COMPLETED", {
                "registrar_protocolo": {"protocolo_id": "PRT-200", "protocol_closed": True},
                "abrir_contestacao_cliente": {"success": True, "contested_items": [{"itemName": "TIM Fashion Mensal", "status": "INICIADA"}], "protocol_closed": True},
            })

    runtime = Runtime()
    monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
    monkeypatch.setattr(main, "service", _Service())
    result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "TIM Fashion Mensal", "valor": "14,99"})
    assert result["success"] is True
    assert result["protocol_closed"] is True
    assert result["contestacao_protocol"] == "PRT-200"

@pytest.mark.asyncio
async def test_sms_flag_interno_nao_vaza_no_contrato_externo(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.i = 0
        async def arun(self, name, payload, execution_id=None):
            self.i += 1
            if self.i == 1:
                return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
                    "results": [{"success": True, "subject": "Conteudo Premium", "msisdn": payload["msisdn"]}],
                    "contestation_candidates": [{"success": True, "subject": "Conteudo Premium", "msisdn": payload["msisdn"]}],
                }})
            return _result(name, "COMPLETED", {
                "registrar_protocolo": {"protocolo_id": "PRT-201"},
                "abrir_contestacao_cliente": {"success": True},
                "enviar_sms": {"success": True, "sms_sent": True},
            })

    runtime = Runtime()
    monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
    monkeypatch.setattr(main, "service", _Service())
    result = await main._run_cancelamento_com_contestacao({"msisdn": "5511988887777", "subject": "Conteudo Premium", "valor": "9,90"})
    assert result["contestacao_protocol"] == "PRT-201"
    assert "sms_sent" not in result
    assert result["sms_not_send_error"] is False


@pytest.mark.asyncio
async def test_cancelamento_com_protocolo_sem_item_contestado_continua_resolvido(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.i = 0
        async def arun(self, name, payload, execution_id=None):
            self.i += 1
            if self.i == 1:
                return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
                    "cancelados": [{"msisdn": payload["msisdn"], "servico": "Tamboro Mensal"}],
                    "itens_para_contestacao": [{"msisdn": payload["msisdn"], "subject": "Tamboro Mensal"}],
                    "protocolos_por_linha": [{"msisdn": payload["msisdn"], "protocolo_id": "PRT-CANCEL-1"}],
                }})
            return _result(name, "COMPLETED", {
                "registrar_protocolo": {"protocolo_id": "PRT-CONTEST-1"},
                "abrir_contestacao_cliente": {"success": True, "contested_items": [], "not_contested_items": [], "contested_invoice_amount_open": "0"},
            })

    runtime = Runtime()
    monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
    monkeypatch.setattr(main, "service", _Service())
    result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "Tamboro Mensal", "valor": "14,99"})
    assert result["success"] is True
    assert result["recomenda_finalizacao"] is True
    assert result["status_finalizacao_sugerido"] == "resolvido"
    assert result["protocols_for_response"] == ["PRT-CANCEL-1", "PRT-CONTEST-1"]


@pytest.mark.asyncio
async def test_falha_sms_e_propagada_sem_expor_sms_sent(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.i = 0
        async def arun(self, name, payload, execution_id=None):
            self.i += 1
            if self.i == 1:
                return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
                    "results": [{"success": True, "subject": "TIM Fashion Mensal", "msisdn": payload["msisdn"]}],
                    "contestation_candidates": [{"success": True, "subject": "TIM Fashion Mensal", "msisdn": payload["msisdn"]}],
                }})
            return _result(name, "COMPLETED", {
                "registrar_protocolo": {"protocolo_id": "PRT-101"},
                "abrir_contestacao_cliente": {"success": True},
                "enviar_sms": {"success": False, "sms_sent": False, "sms_not_send_error": True},
            })

    runtime = Runtime()
    monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
    monkeypatch.setattr(main, "service", _Service())
    result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "TIM Fashion Mensal", "valor": "14,99"})
    assert result["success"] is True
    assert result["sms_not_send_error"] is True
    assert "sms_sent" not in result

@pytest.mark.asyncio
async def test_candidato_explicito_e_contestado_mesmo_sem_cancelamento_bem_sucedido(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.i = 0; self.calls=[]
        async def arun(self, name, payload, execution_id=None):
            self.i += 1; self.calls.append((name, payload))
            if self.i == 1:
                return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
                    "results": [{"success": False, "subject": "Inexistente", "reason": "service_not_found", "error": "não encontrado"}],
                    "contestation_candidates": [{"success": False, "subject": "Inexistente", "msisdn": payload["msisdn"], "iu_reason": "service_not_found"}],
                }})
            return _result(name, "COMPLETED", {
                "registrar_protocolo": {"protocolo_id": "PRT-CANDIDATO"},
                "abrir_contestacao_cliente": {"success": True, "contested_items": [{"itemName": "Inexistente", "status": "INICIADA"}]},
            })

    runtime = Runtime()
    monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
    monkeypatch.setattr(main, "service", _Service())
    result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "Inexistente", "valor": "14,99"})
    assert [x[0] for x in runtime.calls] == ["cancelamento_vas_avulso", "contestacao_tool"]
    assert runtime.calls[1][1]["items"][0]["itemName"] == "Inexistente"
    assert runtime.calls[1][1]["items"][0]["claimedAmount"] == "14,99"
    assert result["contestacao_protocol"] == "PRT-CANDIDATO"


@pytest.mark.asyncio
@pytest.mark.parametrize("reason,error", [("block_vas_failed", "Timeout no bloqueio"), ("cancel_vas_failed", "Erro no cancelamento")])
async def test_falha_parcial_rt01_ainda_dispara_rt02(monkeypatch, reason, error):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.i=0; self.calls=[]
        async def arun(self, name, payload, execution_id=None):
            self.i += 1; self.calls.append((name,payload))
            if self.i == 1:
                return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
                    "results": [{"success": False, "subject": "TIM Fashion Mensal", "reason": reason, "error": error}],
                    "nao_cancelados": [{"servico": "TIM Fashion Mensal", "motivo": reason, "erro": error}],
                    "contestation_candidates": [{"subject": "TIM Fashion Mensal", "msisdn": payload["msisdn"], "motivo": reason, "erro": error}],
                }})
            return _result(name, "COMPLETED", {
                "registrar_protocolo": {"protocolo_id": "PRT-RT02"},
                "abrir_contestacao_cliente": {"success": True, "contested_items": [{"itemName": "TIM Fashion Mensal", "status": "INICIADA"}]},
            })

    runtime=Runtime()
    monkeypatch.setattr(main,"get_workflow_runtime",lambda:runtime)
    monkeypatch.setattr(main,"service",_Service())
    result=await main._run_cancelamento_com_contestacao({"msisdn":"5511999999999","subject":"TIM Fashion Mensal","valor":"14,99"})
    assert [x[0] for x in runtime.calls] == ["cancelamento_vas_avulso","contestacao_tool"]
    assert result["contestacao_protocol"] == "PRT-RT02"

@pytest.mark.asyncio
async def test_holder_msisdn_nao_e_trocado_pela_linha_dependente(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.i=0; self.calls=[]
        async def arun(self,name,payload,execution_id=None):
            self.i += 1; self.calls.append((name,payload))
            if self.i == 1:
                return _result(name,"COMPLETED",{"cancelar_vas_avulso":{
                    "results":[{"success":True,"subject":"TIM Fashion Mensal","msisdn":"5511888880000"}],
                    "contestation_candidates":[{"success":True,"subject":"TIM Fashion Mensal","msisdn":"5511888880000"}],
                }})
            return _result(name,"COMPLETED",{"registrar_protocolo":{"protocolo_id":"PRT-FAM"},"abrir_contestacao_cliente":{"success":True}})

    runtime=Runtime()
    monkeypatch.setattr(main,"get_workflow_runtime",lambda:runtime)
    monkeypatch.setattr(main,"service",_Service())
    await main._run_cancelamento_com_contestacao({
        "msisdn":"5511888880000",
        "holder_msisdn":"5511999999999",
        "items":[{"msisdn":"5511888880000","name":"TIM Fashion Mensal","value":"14,99"}],
    })
    assert runtime.calls[0][1]["msisdn"] == "5511999999999"
    assert runtime.calls[1][1]["msisdn"] == "5511999999999"
    assert runtime.calls[1][1]["dependent_invoice_item"] is True


@pytest.mark.asyncio
async def test_item_do_titular_nao_e_marcado_como_dependente(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.i=0; self.calls=[]
        async def arun(self,name,payload,execution_id=None):
            self.i += 1; self.calls.append((name,payload))
            if self.i == 1:
                return _result(name,"COMPLETED",{"cancelar_vas_avulso":{
                    "results":[{"success":True,"subject":"TIM Games","msisdn":"5511999999999"}],
                    "contestation_candidates":[{"success":True,"subject":"TIM Games","msisdn":"5511999999999"}],
                }})
            return _result(name,"COMPLETED",{"registrar_protocolo":{"protocolo_id":"PRT-TIT"},"abrir_contestacao_cliente":{"success":True}})

    runtime=Runtime()
    monkeypatch.setattr(main,"get_workflow_runtime",lambda:runtime)
    monkeypatch.setattr(main,"service",_Service())
    await main._run_cancelamento_com_contestacao({"msisdn":"5511999999999","subject":"TIM Games","valor":"9,90"})
    assert runtime.calls[1][1]["dependent_invoice_item"] is False


@pytest.mark.asyncio
async def test_titular_e_dependentes_permancem_em_uma_unica_contestacao(monkeypatch):
    import contas_mcp.servers.contas_mcp_server.main as main

    class Runtime:
        def __init__(self): self.i=0; self.calls=[]
        async def arun(self,name,payload,execution_id=None):
            self.i += 1; self.calls.append((name,payload))
            if self.i == 1:
                cands=[
                    {"success":True,"subject":"TIM Games","msisdn":"5511999999999"},
                    {"success":True,"subject":"TIM Fashion Mensal","msisdn":"5511888880000"},
                    {"success":True,"subject":"Tamboro Mensal","msisdn":"5511777770000"},
                ]
                return _result(name,"COMPLETED",{"cancelar_vas_avulso":{"results":cands,"contestation_candidates":cands}})
            return _result(name,"COMPLETED",{"registrar_protocolo":{"protocolo_id":"PRT-FAM-3"},"abrir_contestacao_cliente":{"success":True}})

    runtime=Runtime()
    monkeypatch.setattr(main,"get_workflow_runtime",lambda:runtime)
    monkeypatch.setattr(main,"service",_Service())
    await main._run_cancelamento_com_contestacao({
        "msisdn":"5511999999999",
        "items":[
            {"msisdn":"5511999999999","name":"TIM Games","value":"9,90"},
            {"msisdn":"5511888880000","name":"TIM Fashion Mensal","value":"14,99"},
            {"msisdn":"5511777770000","name":"Tamboro Mensal","value":"8,50"},
        ],
    })
    assert [x[0] for x in runtime.calls] == ["cancelamento_vas_avulso","contestacao_tool"]
    contest=runtime.calls[1][1]
    assert contest["msisdn"] == "5511999999999"
    assert {x["itemName"] for x in contest["items"]} == {"TIM Games","TIM Fashion Mensal","Tamboro Mensal"}
    assert contest["dependent_invoice_item"] is True
