from __future__ import annotations
from datetime import datetime, timedelta
from types import SimpleNamespace

from app.domain.contas.contestation_rules import (
    complete_invoices_context, resolve_refund_option, billing_cutoff_reference,
    next_cutoff_from_cut_date, due_day, manual_conta_certa_from_evidence,
)
from app.domain.contas.workflow_actions import build_contas_workflow_actions


def _complete(status='Em aberto', payment_type=2, cut_date=None):
    row={'invoiceId':'I1','invoiceStatus':status,'dueDate':'2026-08-25'}
    if cut_date is not None: row['cutDate']=cut_date
    return {'billingProfile':{'paymentTypeId':payment_type},'paymentItems':[row]}


def test_refund_boleto_para_fatura_em_aberto_com_fatura_normal():
    c=complete_invoices_context(_complete('Em aberto',2),'I1')
    r=resolve_refund_option(payment_method=c['payment_method'],has_open_bill=c['has_open_bill'],invoice_statuses=c['invoice_statuses'])
    assert r['refund_option']=='1' and r['format_text']=='sms'


def test_refund_credito_para_dacc_cartao_ou_parcelamento():
    for method in ('DACC|Cartão|Parcelamento','debito_automatico','cartao_credito'):
        r=resolve_refund_option(payment_method=method,has_open_bill=True,invoice_statuses=['Em aberto'])
        assert r['refund_option']=='0'


def test_refund_credito_para_fatura_paga_ou_ja_contestada():
    for status in ('Pago','Contestada'):
        r=resolve_refund_option(payment_method='fatura',has_open_bill=False,invoice_statuses=[status])
        assert r['refund_option']=='0'


def test_cutoff_referencia_corrige_bug_mes_seguinte():
    ref=datetime(2026,8,18,12)
    passed, cutoff=billing_cutoff_reference(10,reference_datetime=ref)
    assert passed is True and cutoff.date().isoformat()=='2026-08-10'
    passed2, cutoff2=billing_cutoff_reference(25,reference_datetime=ref)
    assert passed2 is True and cutoff2.date().isoformat()=='2026-07-25'


def test_cutdate_regra_um_mes():
    ref=datetime(2026,8,18)
    assert next_cutoff_from_cut_date(datetime(2026,6,1),reference_datetime=ref)[0] is True
    assert next_cutoff_from_cut_date(datetime(2026,8,1),reference_datetime=ref)[0] is False


def test_due_day_iso_e_br():
    assert due_day('2026-08-25')==25
    assert due_day('25/08/2026')==25


def test_dependente_forca_conta_certa_manual():
    assert manual_conta_certa_from_evidence(dependent_invoice_item=True) is True


def test_cutdate_da_fatura_define_manual():
    ref=datetime(2026,8,18)
    assert manual_conta_certa_from_evidence(invoice_item={'cutDate':'2026-06-01'},reference_datetime=ref) is True
    assert manual_conta_certa_from_evidence(invoice_item={'cutDate':'2026-08-01'},reference_datetime=ref) is False


def test_check_invoice_status_enriquece_prefetch_sem_nova_api():
    class Client:
        def consultar_faturas(self,*a,**k): raise AssertionError('não deve chamar API')
    class Service: client=Client()
    a=build_contas_workflow_actions(Service()).get('check_invoice_status')
    out=a({'complete_invoices_payload':_complete('Em aberto',3),'invoice_id':'I1'}, {'input':{},'vars':{}})
    assert out['success'] is True
    assert out['invoice_status']=='Em aberto'
    assert out['has_open_bill'] is True
    assert out['payment_type_id']==3
    assert out['requires_sms'] is True


def test_check_invoice_status_falha_sem_prefetch():
    class Service: pass
    a=build_contas_workflow_actions(Service()).get('check_invoice_status')
    try:
        a({'invoice_id':'I1'},{'input':{},'vars':{}})
    except RuntimeError as exc:
        assert 'prefetch' in str(exc)
    else:
        raise AssertionError('deveria falhar sem prefetch')


def test_abrir_contestacao_deriva_refund_manual_e_normaliza_barcode_zero():
    captured={}
    class Client:
        def billing_analysis(self,msisdn): return {'119':{'SVA Detalhe Total':[{'desc':'VAS Musica','value':29.90}]}}
        def contrato(self,msisdn): return {'billing_profile':{'date':{'cutoffDay':1}}}
        def contestar(self,payload):
            captured.update(payload)
            return {'itemsResponse':[{'status':'CRIAR','itemName':'VAS Musica','correctAccountStatus':'CRIAR'}],'barcode':'0'*44}
    class Service: client=Client()
    a=build_contas_workflow_actions(Service()).get('abrir_contestacao_cliente')
    complete=_complete('Em aberto',2)
    state={'input':{},'vars':{'check_invoice_status':{'complete_invoices_payload':complete,**complete_invoices_context(complete,'I1')}}}
    out=a({'msisdn':'119','social_sec_no':'123','customer_id':'C1','invoice_id':'I1','items':[{'itemName':'VAS Musica','claimedAmount':'29,90','validatedAmount':'29,90'}],'protocolo_id':'P1','skip_invoice_item_validation':True},state)
    assert captured['refundOption']=='1'
    assert captured['manualContaCertaIndicator'] is True
    assert captured['contestationType']=='0'
    assert captured['adjustReason']=='SERVICO_NAO_SOLICITADO'
    assert out['barcode']==''
    assert out['conta_certa_status']=='CRIAR'
