import { useEffect, useState } from 'react'; import { exportMonthlyCashflowCsv, projectMonthlyCashflow, defaultCashflowDraftInputs, restoreCashflowDraftSnapshot, serializeCashflowDraftSnapshot, cashflowCurrency, type CashflowDraftSnapshot, } from '@/lib/monthly-cashflow'; import { isSimulationCurrency, simulationCurrencyOptions, } from '@/lib/simulation-contract'; export function SimulationCashflowPlanner({ currency, onCurrencyChange, snapshot, onSnapshotChange, }: { currency: string; onCurrencyChange: (currency: string) => void; snapshot?: string; onSnapshotChange?: (snapshot: string) => void; }) { const restored = restoreCashflowDraftSnapshot(snapshot); const [confirmedCurrency, setConfirmedCurrency] = useState(''); const originCurrency = restored?.version === 2 ? restored.currency : null; const calculationCurrency = snapshot ? (originCurrency ?? '') : currency; const [taxMode, setTaxMode] = useState<'fixed' | 'schedule'>( restored?.taxMode ?? 'fixed', ); const [inputs, setInputs] = useState( restored?.inputs ?? defaultCashflowDraftInputs(), ); useEffect(() => { const saved = restoreCashflowDraftSnapshot(snapshot); setTaxMode(saved?.taxMode ?? 'fixed'); setInputs(saved?.inputs ?? defaultCashflowDraftInputs()); }, [snapshot]); function update( next: typeof inputs, mode: CashflowDraftSnapshot['taxMode'] = taxMode, ) { setInputs(next); setTaxMode(mode); onSnapshotChange?.( serializeCashflowDraftSnapshot( mode, next, snapshot ? (originCurrency ?? null) : currency || null, ), ); } const set = ( key: Exclude, value: string, ) => update({ ...inputs, [key]: value }); const cashflowInput = { ...inputs, ...(taxMode === 'fixed' ? { monthlyTaxSchedule: undefined } : { monthlyTaxAssessed: '', monthlyTaxSchedule: inputs.monthlyTaxSchedule, }), }; let projection; let error = ''; try { if (snapshot && !restored) throw new Error( 'Não foi possível recuperar os pressupostos guardados de tesouraria. Reveja os campos antes de voltar a guardar; nenhum resultado foi calculado com dados alternativos.', ); if (restored) cashflowCurrency(restored, currency); projection = projectMonthlyCashflow({ ...cashflowInput, currency: calculationCurrency, }); } catch (cause) { error = cause instanceof Error ? cause.message : 'Verifique os valores introduzidos.'; } return (
{simulationCurrencyOptions.map((code) => ( ))}

Projecção de tesouraria — 12 meses

{restored && !originCurrency && (

A moeda de origem dos montantes guardados não foi registada. Os valores foram conservados. Confirme apenas essa moeda; não é necessário preencher os montantes novamente.

)} {originCurrency && originCurrency !== currency && (

{cashflowCurrency(restored!, currency).notice}

)} {originCurrency && (

Moeda de origem dos pressupostos: {originCurrency}.

)}

Introduza pressupostos na mesma moeda. O imposto indicado é um pressuposto do utilizador; esta ferramenta não calcula nem confirma uma obrigação fiscal. Crédito estimado, pedido e montante reconhecido são informativos e não contam como caixa. Apenas o recebimento previsto entra no mês indicado, como hipótese não garantida.

{restored ? 'Pressupostos recuperados do rascunho deste investimento; reveja-os antes de interpretar os resultados ou exportar.' : snapshot ? 'O rascunho guardado não pôde ser interpretado. Os campos mostram exemplos, que não substituem os dados guardados até os editar.' : 'Os valores preenchidos ao abrir são exemplos demonstrativos. Confirme ou altere os pressupostos antes de interpretar os resultados ou exportar o CSV.'}

{projection?.status === 'incomplete' && (

Há pelo menos um mês sem pressuposto de imposto: o saldo total desde esse ponto é indeterminado. A caixa conhecida inclui os impostos declarados e omite apenas os meses em falta; mês vazio não significa imposto zero.

)}
Pressuposto de imposto para planeamento {taxMode === 'fixed' ? ( ) : (
{inputs.monthlyTaxSchedule.map((value, index) => ( ))}
)}
{( [ ['openingCash', 'Saldo inicial'], ['monthlyRevenue', 'Receita mensal'], [ 'monthlyOperatingCosts', 'Custos operacionais mensais', ], ['monthlyDebtService', 'Prestação mensal'], [ 'vatCreditEstimated', 'Crédito de IVA estimado (não caixa)', ], [ 'vatRefundRequested', 'Reembolso de IVA pedido (não caixa)', ], [ 'vatRefundRecognized', 'Reembolso reconhecido (não caixa)', ], [ 'vatRefundExpectedReceipt', 'Recebimento IVA previsto (condicional)', ], [ 'vatRefundExpectedMonth', 'Mês previsto do recebimento (1–12)', ], ] as const ).map(([key, label]) => ( ))}
{error && (

{error}

)} {projection && isSimulationCurrency(calculationCurrency) && ( <>

{projection.endingCash === null ? `Caixa conhecida antes de imposto em falta, ao fim de 12 meses (${calculationCurrency}):` : `Saldo projectado ao fim de 12 meses (${calculationCurrency}):`}{' '} {projection.endingCash ?? projection.endingCashBeforeUnassessedTax}

{projection.firstDeficitMonth && ( O saldo após o imposto declarado fica negativo no mês {projection.firstDeficitMonth}. )} {!projection.firstDeficitMonth && projection.firstDeficitMonthBeforeUnassessedTax && ( Os fluxos conhecidos já deixam o caixa negativo, antes do imposto não informado, no mês{' '} { projection.firstDeficitMonthBeforeUnassessedTax } . )}

Crédito estimado: {projection.vatCreditEstimated}; pedido: {projection.vatRefundRequested}; reconhecido:{' '} {projection.vatRefundRecognized}. Estes valores não foram somados à caixa.

{[ 'Mês', 'Saldo inicial', 'Receitas', 'Custos', 'Dívida', 'Imposto assumido', 'Reembolso previsto', 'Fluxo antes de imposto em falta', 'Caixa antes de imposto em falta', 'Fluxo líquido total', 'Saldo final total', ].map((value) => ( ))} {projection.rows.map((row) => ( ))}
Projecção mensal de tesouraria
{value}
{row.month} {row.openingCash ?? 'Indeterminado'} {row.revenue} {row.operatingCosts} {row.debtService} {row.taxAssessed ?? 'Indeterminado'} {row.vatRefundExpectedReceipt} {row.netFlowBeforeUnassessedTax} {row.closingCashBeforeUnassessedTax} {row.netFlow ?? 'Indeterminado'} {row.closingCash ?? 'Indeterminado'}
)}
); }