from datetime import datetime from typing import Optional from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from sqlalchemy.orm import Session from app.database.database import get_db from app.database.models import Goal, User router = APIRouter(prefix="/api/goals", tags=["Goals"]) def _resolve_user(db: Session, user_id: Optional[str]) -> str: if user_id: return user_id user = db.query(User).first() if not user: raise HTTPException(status_code=404, detail="No users found. Seed the database first.") return user.id class ContributeRequest(BaseModel): amount: float = Field(gt=0) @router.get("") def list_goals(user_id: Optional[str] = None, db: Session = Depends(get_db)): uid = _resolve_user(db, user_id) goals = db.query(Goal).filter(Goal.user_id == uid).order_by(Goal.target_date.asc()).all() items = [] total_target = 0.0 total_saved = 0.0 for g in goals: progress = min(100.0, (g.current_amount / g.target_amount * 100) if g.target_amount > 0 else 0) total_target += g.target_amount total_saved += g.current_amount days_left = None if g.target_date: days_left = max(0, (g.target_date.replace(tzinfo=None) - datetime.utcnow()).days) plan = g.ai_generated_plan or {} items.append({ "id": g.id, "title": g.title, "target_amount": g.target_amount, "current_amount": g.current_amount, "progress_percent": round(progress, 1), "target_date": g.target_date.isoformat() if g.target_date else None, "days_left": days_left, "monthly_contribution": plan.get("monthly_contribution"), "months_remaining": plan.get("months_remaining"), "on_track": progress >= 50 or (days_left is not None and days_left > 180), }) return { "goals": items, "summary": { "count": len(items), "total_target": round(total_target, 2), "total_saved": round(total_saved, 2), "overall_progress": round(total_saved / total_target * 100, 1) if total_target > 0 else 0, }, } @router.post("/{goal_id}/contribute") def contribute_to_goal( goal_id: str, body: ContributeRequest, user_id: Optional[str] = None, db: Session = Depends(get_db), ): uid = _resolve_user(db, user_id) goal = db.query(Goal).filter(Goal.id == goal_id, Goal.user_id == uid).first() if not goal: raise HTTPException(status_code=404, detail="Goal not found") goal.current_amount = min(goal.target_amount, goal.current_amount + body.amount) db.commit() db.refresh(goal) progress = min(100.0, goal.current_amount / goal.target_amount * 100) if goal.target_amount > 0 else 0 return { "id": goal.id, "current_amount": goal.current_amount, "progress_percent": round(progress, 1), "completed": goal.current_amount >= goal.target_amount, }