from __future__ import annotations

import json

from agent_framework.analytics.tim_payload_mapper import map_analytics_event_to_tim_flat_payload
from app.domain.contas.workflow_actions import build_contas_workflow_actions


def _event(result: dict, code: str) -> dict:
    return next(x for x in result.get("business_events", []) if x.get("code") == code)


def test_contestacao_vaa_metadata_preserva_contexto_tim_original():
    class Client:
        def billing_analysis(self, msisdn):
            return {"currentInvoice": [{"desc": "Serviços de valor adicionado", "items": [{"desc": "VAS Musica", "value": 29.9, "classe": "avulso"}]}]}

        def contestar(self, payload):
            return {"barcode": "8469", "itemsResponse": []}

    class Service:
        client = Client()

    action = build_contas_workflow_actions(Service()).get("abrir_contestacao_cliente")
    state = {
        "input": {
            "session_id": "sess-1",
            "message_id": "msg-1",
            "ura_call_id": "CALL-123",
            "channel_id": "URA",
        }
    }
    result = action(
        {
            "msisdn": "11999998888",
            "protocolo_id": "PRT-11",
            "invoice_id": "3000135012",
            "servico": "VAS Musica",
            "valor": 29.9,
        },
        state,
    )
    payload = _event(result, "VAA.006")["payload"]
    assert payload["agentId"] == "contas"
    assert payload["channelId"] == "URA"
    assert payload["gsm"] == "11999998888"
    assert payload["uraCallId"] == "CALL-123"
    assert payload["sessionId"] == "sess-1"
    assert payload["messageId"] == "msg-1"
    assert payload["agentProtocolId"] == "PRT-11"
    assert payload["adjustedProtocol"] == "PRT-11"
    assert payload["billingId"] == "3000135012"
    assert payload["adjustedItems"] == ["VAS Musica"]
    assert payload["adjustedItemsAmount"] == ["29.9"]
    assert json.loads(payload["agentSpecificData"]) == {
        "adjustedItems": ["VAS Musica"],
        "adjustedItemsAmount": ["29.9"],
    }


def test_contestacao_vaa007_falha_preserva_protocolo_e_itens():
    class Client:
        def billing_analysis(self, msisdn):
            return {"currentInvoice": [{"desc": "Serviços de valor adicionado", "items": [{"desc": "VAS Musica", "value": 29.9, "classe": "avulso"}]}]}

        def contestar(self, payload):
            raise RuntimeError("falha provider")

    class Service:
        client = Client()

    action = build_contas_workflow_actions(Service()).get("abrir_contestacao_cliente")
    result = action(
        {"msisdn": "119", "protocolo_id": "PRT-11", "invoice_id": "INV-1", "servico": "VAS Musica", "valor": 29.9},
        {"input": {"channel_id": "URA", "ura_call_id": "CALL-1"}},
    )
    payload = _event(result, "VAA.007")["payload"]
    assert payload["agentProtocolId"] == "PRT-11"
    assert payload["adjustedProtocol"] == "PRT-11"
    assert payload["adjustedItems"] == ["VAS Musica"]
    assert payload["adjustedItemsAmount"] == ["29.9"]


def test_tim_payload_mapper_aceita_agent_specific_data_json_string_historico():
    mapped = map_analytics_event_to_tim_flat_payload(
        "VAA.006",
        {
            "eventType": "VAA.006",
            "payload": {
                "tag": "VAA.006",
                "agentProtocolId": "P1",
                "agentSpecificData": '{"billingId":"3000131180","item":"VAS"}',
            },
        },
    )
    assert mapped["agentProtocolId"] == "P1"
    assert mapped["agentSpecificData"] == {"billingId": "3000131180", "item": "VAS"}


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

    class Client:
        def abrir_protocolo(self, payload):
            return {"interactionProtocol": "INFO-123"}
        def status_sr(self, payload):
            return {"ok": True}

    action = build_contas_workflow_actions(ContasDomainService(client=Client())).get("finalizar_atendimento_action")
    result = action(
        {
            "status": "resolvido",
            "summary": "ok",
            "msisdn": "11999999999",
            "social_sec_no": "123",
            "session_id": "sess-final",
            "message_id": "msg-final",
            "ura_call_id": "CALL-FINAL",
            "ura_protocol_id": "URA-123",
            "channel_id": "URA",
            "invoice_id": "3000131180",
            "business_workflows_executed": ["invoice_explanation"],
            "invoice_explanation_base": "Explicação.",
        },
        {"input": {}},
    )
    payload = _event(result, "CVN.010")["payload"]
    assert payload["agentProtocolId"] == "INFO-123"
    assert payload["adjustedProtocol"] == "INFO-123"
    assert payload["uraProtocolId"] == "URA-123"
    assert payload["uraCallId"] == "CALL-FINAL"
    assert payload["channelId"] == "URA"
    assert payload["billingId"] == "3000131180"
    assert json.loads(payload["agentSpecificData"]) == {"billingId": "3000131180"}


def test_vas_estrategico_veb_preserva_turno_e_contexto_ura():
    class Client:
        def abrir_protocolo(self, payload):
            return {"interactionProtocol": "VEB-123"}

    class Service:
        client = Client()

    action = build_contas_workflow_actions(Service()).get("registrar_atendimento_vas_estrategico")
    result = action(
        {
            "linhas": [{"msisdn": "5511999999999"}],
            "mensagem_base": "Informação sobre cancelamento.",
        },
        {
            "input": {
                "resposta_usuario": "NAO",
                "customer_message": "Não quero manter o serviço.",
                "ura_call_id": "155344608",
                "channel_id": "ura",
                "message_id": "msg-005",
            }
        },
    )
    codes = [x["code"] for x in result["business_events"]]
    assert codes == ["VEB.004", "VEB.006", "VEB.007"]
    payload = _event(result, "VEB.004")["payload"]
    assert payload["uraCallId"] == "155344608"
    assert payload["channelId"] == "ura"
    assert payload["messageId"] == "msg-005"
    assert payload["customerMessage"] == "NAO"
    assert payload["llmResponse"] == "Informação sobre cancelamento."


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

    class Client:
        def abrir_protocolo(self, payload):
            return {"interactionProtocol": "INFO-321"}
        def status_sr(self, payload):
            return {"ok": True}

    action = build_contas_workflow_actions(ContasDomainService(client=Client())).get("finalizar_atendimento_action")
    result = action(
        {
            "status": "resolvido",
            "summary": "Cliente entendeu.",
            "msisdn": "11999999999",
            "invoice_id": "3000131180",
            "business_workflows_executed": ["invoice_explanation"],
            "invoice_explanation_base": "Explicação dos valores da fatura",
            "customer_message": "Sim, entendi",
            "llm_response": "Perfeito, fico feliz em ajudar.",
            "message_id": "msg-final",
            "session_id": "sess-final",
            "channel_id": "URA",
            "ura_call_id": "CALL-FINAL",
            "session_end_at": "2026-06-11T12:00:00Z",
        },
        {"input": {}},
    )
    mpi = _event(result, "MPI.006")["payload"]
    assert mpi["customerMessage"] == "Sim, entendi"
    assert mpi["llmResponse"] == "Perfeito, fico feliz em ajudar."
    assert mpi["billingId"] == "3000131180"
    assert mpi["messageId"] == "msg-final"
    assert mpi["sessionId"] == "sess-final"

    sad = _event(result, "SAD.001")["payload"]
    assert sad["llmResponse"] == "Perfeito, fico feliz em ajudar."
    assert sad["messageId"] == "msg-final"
    assert sad["sessionEndAt"] == 1781179200000


def test_vas_bundle_nao_defera_protocolo_e_emite_veb005():
    class Client:
        def __init__(self): self.calls = 0
        def abrir_protocolo(self, payload):
            self.calls += 1
            return {"interactionProtocol": "SHOULD-NOT-HAPPEN"}

    client = Client()
    class Service: pass
    service = Service(); service.client = client
    action = build_contas_workflow_actions(service).get("registrar_atendimento_vas_estrategico")
    result = action(
        {
            "linhas": [{"msisdn": "5511999999999", "bundle_names": ["TIM Segurança"]}],
            "mensagem_base": "Bundle incluso no plano.",
        },
        {"input": {"resposta_usuario": "NAO", "ura_call_id": "CALL-1", "channel_id": "URA", "message_id": "M1"}},
    )
    assert [x["code"] for x in result["business_events"]] == ["VEB.004", "VEB.005", "VEB.007"]
    assert client.calls == 0
    assert result["protocol_closed"] is False
    assert result["protocol_deferred_to_finalization"] is True
    assert result["suppress_cvn_protocol_ic"] is True
    assert result["informational_vas_types"] == ["bundle"]


def test_invoice_explanation_mpi005_preserva_turno_e_contexto():
    class Service: pass
    action = build_contas_workflow_actions(Service()).get("registrar_atendimento_invoice_explanation")
    result = action(
        {"caminho": "NAO", "invoice_id": "INV-9"},
        {"input": {"customer_message": "Ainda não entendi", "message_id": "M9", "session_id": "S9", "channel_id": "URA", "ura_call_id": "C9"}},
    )
    payload = _event(result, "MPI.005")["payload"]
    assert payload["customerMessage"] == "Ainda não entendi"
    assert payload["messageId"] == "M9"
    assert payload["sessionId"] == "S9"
    assert payload["channelId"] == "URA"
    assert payload["uraCallId"] == "C9"
    assert payload["billingId"] == "INV-9"


def test_pro_rata_mpi010_preserva_contexto_do_turno():
    class Service: pass
    action = build_contas_workflow_actions(Service()).get("preparar_pro_rata")
    result = action(
        {"planos": [], "msisdn": "11999999999"},
        {"input": {"customer_message": "Por que veio proporcional?", "message_id": "MP1", "session_id": "SP1", "channel_id": "web"}},
    )
    payload = _event(result, "MPI.010")["payload"]
    assert payload["gsm"] == "11999999999"
    assert payload["customerMessage"] == "Por que veio proporcional?"
    assert payload["messageId"] == "MP1"
    assert payload["sessionId"] == "SP1"
    assert payload["channelId"] == "web"
