"""Insights module — now robust, graceful, and category-aware."""
from utils.budget_core import (
get_budget_for_month,
calculate_remaining_budget,
get_current_month
)
from utils.expenses_core import get_expenses_by_month
from utils.date_utils import get_days_remaining_in_month, parse_flexible_month
from utils.category_detection import detect_category
def register_insight_tools(mcp):
@mcp.tool()
def get_affordability_insights(month: str = '') -> dict:
"""Produce high-level spending guidance with graceful fallbacks."""
# Resolve month
try:
target = parse_flexible_month(month) if month else get_current_month()
except Exception:
return {
"status": "needs_clarification",
"message": f"I couldn't understand '{month}'.",
"suggestion": "Try something like 'Jan 2025', 'this month', or '2024-12'."
}
# Check budget exists
b = get_budget_for_month(target)
if not b:
return {
"status": "no_budget",
"message": f"No budget exists for {target}.",
"options": [
"Create a new budget",
"View spending insights without budget",
"Analyze expenses by category"
]
}
# Compute remaining budget
success, info = calculate_remaining_budget(target)
if not success:
return {
"status": "soft_error",
"message": "Couldn't compute detailed insights.",
"suggestion": "Would you like a simpler summary of expenses instead?"
}
# Basic spending data
days_left = get_days_remaining_in_month()
total_remaining = info.get("remaining_total", 0)
daily_budget = total_remaining / days_left if days_left > 0 else 0
# Identify categories at risk
critical = []
warning = []
breakdown = info.get("category_breakdown") or info.get("categories") or {}
for cat, data in breakdown.items():
pct = data.get("percentage_used", 0)
rem = data.get("remaining", 0)
if pct >= 90:
critical.append({
"category": cat,
"remaining": rem,
"percentage_used": pct
})
elif pct >= 75:
warning.append({
"category": cat,
"remaining": rem,
"percentage_used": pct
})
# Suggestions
suggestions = [
f"Try to spend under ₹{daily_budget:.2f} per day for the rest of the month.",
]
if critical:
suggestions.append("Some categories are nearly exhausted — consider reducing spending there.")
if total_remaining < 0:
suggestions.append("You’ve exceeded your total budget — consider pausing non-essential spending.")
return {
"status": "ok",
"month": target,
"budget_mode": info.get("budget_mode"),
"insights": {
"days_remaining": days_left,
"daily_budget": round(daily_budget, 2),
"total_remaining": round(total_remaining, 2),
"critical_categories": critical,
"warning_categories": warning,
"suggestions": suggestions
},
"overview": {
"total_budget": info.get("total_budget"),
"total_spent": info.get("total_spent"),
"utilization_percentage": info.get("utilization_percentage")
}
}