from sqlalchemy.orm import Session from app.database.models import Account, Goal, Investment, Subscription from app.ai.forecasting import get_cashflow_metrics def simulate_purchase_impact(db: Session, user_id: str, amount: float, category: str, merchant: str): """ Simulates buying a large asset or item (e.g. a car) and assesses risk. """ accounts = db.query(Account).filter(Account.user_id == user_id).all() total_balance = sum(acc.balance for acc in accounts) checking_acc = next((a for a in accounts if a.type.lower() == "checking"), None) # Target emergency fund amount goals = db.query(Goal).filter(Goal.user_id == user_id).all() emergency_goal = next((g for g in goals if "emergency" in g.title.lower()), None) emergency_threshold = emergency_goal.target_amount if emergency_goal else 3000.0 new_balance = total_balance - amount # Cashflow metrics _, daily_income, daily_spending = get_cashflow_metrics(db, user_id) monthly_net = (daily_income - daily_spending) * 30.4 # Risk Analysis risk_level = "low" reasons = [] if amount > total_balance: risk_level = "critical" reasons.append("Purchase exceeds your total available balance, requiring debt.") elif new_balance < emergency_threshold: risk_level = "high" reasons.append(f"This purchase depletes your emergency buffer (threshold of ${emergency_threshold:,.2f}).") elif amount > total_balance * 0.3: risk_level = "medium" reasons.append("Single purchase consumes more than 30% of your total liquid cash.") if monthly_net < 0 and amount > 500: risk_level = "high" reasons.append("You have a negative monthly cashflow; making large purchases increases financial strain.") # Recommendations recommendation = "" if risk_level == "critical": recommendation = "❌ Strongly advise against this purchase. Consider financing options, delaying, or establishing a dedicated goal." elif risk_level == "high": recommendation = "⚠️ Refrain from this purchase if possible. Rebuilding your emergency fund should be prioritized." elif risk_level == "medium": recommendation = "💡 Proceed with caution. Consider trimming discretionary expenses next month to offset the cost." else: recommendation = "✅ Purchase is safe. It fits within your financial profile without impacting key safety buffers." return { "purchase_amount": amount, "merchant": merchant, "category": category, "current_balance": round(total_balance, 2), "projected_balance": round(max(0.0, new_balance), 2), "savings_impact": { "immediate_reduction": round(amount, 2), "emergency_buffer_breached": new_balance < emergency_threshold, "emergency_threshold": round(emergency_threshold, 2) }, "risk_analysis": { "risk_level": risk_level, "reasons": reasons }, "recommendation": recommendation } def simulate_investment_impact(db: Session, user_id: str, monthly_sip: float, asset_type: str, lump_sum: float = 0.0): """ Simulates investment growth and evaluates opportunity cost. """ # Expected annual returns based on asset type returns_map = { "stock": 0.10, # 10% "crypto": 0.20, # 20% "mutual_fund": 0.08, # 8% "fd": 0.05, # 5% "bond": 0.04 # 4% } apr = returns_map.get(asset_type.lower(), 0.07) # Calculate current balance accounts = db.query(Account).filter(Account.user_id == user_id).all() total_balance = sum(acc.balance for acc in accounts) # Cashflow metrics _, daily_income, daily_spending = get_cashflow_metrics(db, user_id) monthly_net = (daily_income - daily_spending) * 30.4 # Check if SIP is affordable is_affordable = monthly_net >= monthly_sip growth_projection = [] current_value = lump_sum total_invested = lump_sum # 5-year monthly projection for month in range(0, 61): if month > 0: current_value = (current_value + monthly_sip) * (1 + apr / 12) total_invested += monthly_sip if month in [12, 36, 60]: # Save 1, 3, 5 year markers growth_projection.append({ "year": month // 12, "total_invested": round(total_invested, 2), "future_value": round(current_value, 2), "earnings": round(max(0.0, current_value - total_invested), 2) }) risk_level = "low" if asset_type.lower() == "crypto": risk_level = "high" elif asset_type.lower() in ["stock", "mutual_fund"] and monthly_sip > monthly_net * 0.5: risk_level = "medium" recommendation = "" if not is_affordable: recommendation = f"⚠️ Your monthly net surplus (${monthly_net:,.2f}) is lower than the planned SIP (${monthly_sip:,.2f}). This may lead to checking overdrafts." else: recommendation = f"✅ Excellent choice. Investing ${monthly_sip:,.2f} monthly in {asset_type} is fully supported by your net cashflow." return { "asset_type": asset_type, "monthly_sip": round(monthly_sip, 2), "lump_sum": round(lump_sum, 2), "is_affordable": is_affordable, "growth_projection": growth_projection, "risk_analysis": { "risk_level": risk_level, "expected_annual_return": apr }, "savings_impact": { "opportunity_cost_yearly": round(monthly_sip * 12, 2), "monthly_surplus_retaining": round(max(0.0, monthly_net - monthly_sip), 2) }, "recommendation": recommendation } def simulate_subscription_cancellation(db: Session, user_id: str, subscription_ids: list): """ Simulates the financial benefit of cancelling one or more subscriptions. """ subs = db.query(Subscription).filter( Subscription.user_id == user_id, Subscription.id.in_(subscription_ids) ).all() if not subs: return {"message": "No matching subscriptions found for cancellation simulation."} monthly_savings = 0.0 yearly_savings = 0.0 cancelled_details = [] for sub in subs: cost = sub.amount is_monthly = sub.billing_cycle.lower() == "monthly" m_cost = cost if is_monthly else (cost / 12) y_cost = (cost * 12) if is_monthly else cost monthly_savings += m_cost yearly_savings += y_cost cancelled_details.append({ "id": sub.id, "merchant": sub.merchant, "amount": sub.amount, "billing_cycle": sub.billing_cycle }) # Relate savings to user's Goals goals = db.query(Goal).filter(Goal.user_id == user_id).all() first_goal = goals[0] if goals else None goal_impact = None if first_goal: months_saved = 0.0 remaining_needed = max(0.0, first_goal.target_amount - first_goal.current_amount) if monthly_savings > 0: months_saved = remaining_needed / (remaining_needed / 12 if remaining_needed > 0 else 1) # simple logic # Let's say if they direct this money to goal, it reduces target time by: months_saved = (remaining_needed / monthly_savings) if remaining_needed > 0 else 0 goal_impact = { "goal_title": first_goal.title, "target_amount": round(first_goal.target_amount, 2), "months_to_reach_with_savings": round(months_saved, 1) if monthly_savings > 0 else 0 } # Recommendations recommendation = f"Cancelling these subscriptions yields ${monthly_savings:,.2f} per month (${yearly_savings:,.2f} annually). Reinvesting these funds into high-yield savings or mutual funds is recommended." return { "cancelled_subscriptions": cancelled_details, "monthly_savings": round(monthly_savings, 2), "yearly_savings": round(yearly_savings, 2), "goal_impact": goal_impact, "recommendation": recommendation }