from __future__ import annotations
import asyncio
from types import SimpleNamespace
from typing import Any
from contas_mcp.servers.contas_mcp_server import main as m


def R(status='COMPLETED', output=None, trace=None, error=None, error_details=None):
    d={'execution_id':'x','status':status,'output':output or {},'trace':trace or [],'state':{},'error':error,'error_details':error_details}
    return SimpleNamespace(**d, model_dump=lambda: dict(d))

class Runtime:
    def __init__(self,*rs): self.rs=list(rs); self.calls=[]
    async def arun(self,name,payload,execution_id=None):
        self.calls.append((name,dict(payload),execution_id)); return self.rs.pop(0)


def test_invoice_explanation_preserva_fatura_e_analise_variacao_no_input(monkeypatch):
    rt=Runtime(R(output={}))
    monkeypatch.setattr(m,'get_workflow_runtime',lambda:rt)
    args={'msisdn':'119','invoice_detail':{'119':{'SVA':[]}},'billing_analysis':{'currentInvoice':{'invoiceNumber':'I1'}},'vas_variation':{'added':['X']}}
    asyncio.run(m._run_workflow('invoice_explanation',args))
    p=rt.calls[0][1]
    assert p['invoice_detail']==args['invoice_detail']
    assert p['billing_analysis']==args['billing_analysis']
    assert p['vas_variation']==args['vas_variation']


def test_pro_rata_devolucao_forca_composicao_llm_framework():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class S: pass
    reg=build_contas_workflow_actions(S())
    a=reg.get('orientar_pagamento_pro_rata')
    out=a({'refund_option':'proxima_fatura','valor_ajuste':'10,00'}, {'input':{}})
    assert out.get('requires_llm_composition') is True
    assert str(out.get('response_instruction') or '').strip()


def test_cancelamento_boleto_zerado_ou_nao_nao_vaza_sms_sent(monkeypatch):
    # Independentemente do barcode, o contrato externo não expõe o detalhe interno sms_sent.
    for barcode in ('0'*44,'34191790010104351004791020150008291070026000'):
        cancel=R(output={'cancelar_vas_avulso':{'success':True,'cancelados':[{'servico':'VAS','valor':'9,90','codigo_boleto':barcode,'msisdn':'119'}], 'contestation_candidates':[], 'protocolos_por_linha':[{'protocolo_id':'P1'}]}})
        rt=Runtime(cancel); monkeypatch.setattr(m,'get_workflow_runtime',lambda rt=rt:rt)
        out=asyncio.run(m._run_cancelamento_com_contestacao({'msisdn':'119','subject':'VAS','valor':'9,90'}))
        assert 'sms_sent' not in out
        assert 'prompt_signals' not in out


def test_cancelamento_corrige_linha_item_por_invoice_detail():
    args={'items':[{'msisdn':'111','name':'Filme 2'},{'msisdn':'111','name':'Filme 3'}], 'invoice_detail':{'111':{'SVA':[{'desc':'Filme 2','msisdn':'111'}]},'222':{'SVA':[{'desc':'Filme 3','msisdn':'222'}]}}}
    got=m._normalize_cancel_items(args,'111')
    assert [x['msisdn'] for x in got]==['111','222']


def test_cancelamento_compositor_e_deterministico_sem_diretiva_llm():
    from app.domain.contas.vas_cancellation_message import compose_vas_cancellation_message
    payload={'cancelados':[{'servico':'TIM Fashion Mensal','valor':'14,99'}], 'contested_items':['TIM Fashion Mensal'], 'contested_invoice_amount_open':'14,99', 'contestacao_protocol':'P100'}
    text=compose_vas_cancellation_message(payload)
    assert 'TIM Fashion Mensal' in text and '14,99' in text and 'P100' in text


def test_vas_estrategico_normaliza_nome_e_agrupa_linhas():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class S: pass
    a=build_contas_workflow_actions(S()).get('preparar_vas_estrategico')
    p={'items':[{'msisdn':'111','name':'Paramount plus','type':'estrategico'},{'msisdn':'222','name':'YouTube Premium','type':'estrategico'}]}
    out=a(p,{'input':p})
    assert len(out['linhas'])==2
    names=[n for l in out['linhas'] for n in l.get('estrategico_names',[])]
    assert any('Paramount' in n for n in names)


def test_rag_dominio_apenas_declara_queries_e_framework_executa():
    from app.domain.contas.workflow_actions import build_contas_workflow_actions
    class S: pass
    a=build_contas_workflow_actions(S()).get('buscar_informacao_rag')
    out=a({'query':'como funciona pro rata','queries':['como funciona pro rata'],'top_k':4,'segment':'POS'}, {'input':{}})
    assert out['delegate_to_framework_rag'] is True
    assert out['queries']==['como funciona pro rata']
    assert out['documents']==[]
