File size: 8,324 Bytes
a282d4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
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
    }