import type { CategoryBreakdown, FinanceAnalysis, SimpleFINAccount } from '../types'; export class PersonalFinanceAnalyzer { analyze(accounts: SimpleFINAccount[]): FinanceAnalysis { const assets = accounts.filter((a) => !['CREDIT', 'LOAN'].includes(a.type)); const liabilities = accounts.filter((a) => ['CREDIT', 'LOAN'].includes(a.type)); const totalAssets = assets.reduce((s, a) => s + Math.max(0, a.balance), 0); const totalLiabilities = liabilities.reduce((s, a) => s + Math.abs(Math.min(0, a.balance)), 0); const netWorth = totalAssets - totalLiabilities; const cash = accounts.filter((a) => ['CHECKING', 'SAVINGS'].includes(a.type)); const investments = accounts.filter((a) => a.type === 'INVESTMENT'); const totalCash = cash.reduce((s, a) => s + Math.max(0, a.balance), 0); const totalInvest = investments.reduce((s, a) => s + Math.max(0, a.balance), 0); const allTx = accounts.flatMap((a) => a.transactions); const spending = allTx.filter((tx) => tx.amount < 0 && tx.category !== 'Transfer'); const income = allTx.filter((tx) => tx.amount > 0 && tx.category === 'Income'); const totalSpend = spending.reduce((s, tx) => s + Math.abs(tx.amount), 0); const totalIncome = income.reduce((s, tx) => s + tx.amount, 0); const byCategory: Record = {}; for (const tx of spending) { byCategory[tx.category] = (byCategory[tx.category] ?? 0) + Math.abs(tx.amount); } const categoryBreakdown: CategoryBreakdown[] = Object.entries(byCategory) .sort((a, b) => b[1] - a[1]) .map(([category, amount]) => ({ category, amount, pct: totalSpend > 0 ? ((amount / totalSpend) * 100).toFixed(1) : '0', })); return { netWorth, totalAssets, totalLiabilities, totalCash, totalInvestments: totalInvest, cashPct: totalAssets > 0 ? ((totalCash / totalAssets) * 100).toFixed(1) : '0', investPct: totalAssets > 0 ? ((totalInvest / totalAssets) * 100).toFixed(1) : '0', totalIncome, totalSpend, savingsRate: totalIncome > 0 ? (((totalIncome - totalSpend) / totalIncome) * 100).toFixed(1) : null, categoryBreakdown, accounts, }; } }