from datetime import datetime, timezone from fastapi import APIRouter, Request, Depends, Form from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.templating import Jinja2Templates from sqlalchemy import select, desc from app.models.base import async_session from app.models.user import User from app.models.workout import Phase, Workout, WorkoutSet from app.auth import get_current_user router = APIRouter() templates = Jinja2Templates(directory="app/templates") @router.get("/workouts", response_class=HTMLResponse) async def workout_list(request: Request, user: User = Depends(get_current_user)): async with async_session() as session: result = await session.execute( select(Workout) .where(Workout.user_id == user.id) .order_by(desc(Workout.date)) ) workouts = result.scalars().all() return templates.TemplateResponse(request, "workouts.html", { "user": user, "workouts": workouts, }) @router.get("/workouts/new", response_class=HTMLResponse) async def new_workout_page(request: Request, user: User = Depends(get_current_user)): async with async_session() as session: result = await session.execute(select(Phase)) phases = result.scalars().all() return templates.TemplateResponse(request, "workout_new.html", { "user": user, "phases": phases, }) @router.post("/workouts/new") async def new_workout( request: Request, user: User = Depends(get_current_user), name: str = Form(), date: str = Form(), phase_id: int = Form(default=None), notes: str = Form(default=""), ): async with async_session() as session: workout = Workout( user_id=user.id, phase_id=phase_id, name=name, date=date, notes=notes, status="plan", ) session.add(workout) await session.commit() await session.refresh(workout) workout_id = workout.id return RedirectResponse(url=f"/workouts/{workout_id}", status_code=303) @router.get("/workouts/{workout_id}", response_class=HTMLResponse) async def workout_detail( request: Request, workout_id: int, user: User = Depends(get_current_user), ): async with async_session() as session: result = await session.execute( select(Workout).where( Workout.id == workout_id, Workout.user_id == user.id, ) ) workout = result.scalar_one_or_none() if not workout: return templates.TemplateResponse(request, "404.html", status_code=404) result = await session.execute( select(WorkoutSet) .where(WorkoutSet.workout_id == workout_id) .order_by(WorkoutSet.exercise, WorkoutSet.set_number) ) sets = result.scalars().all() phase = None if workout.phase_id: result = await session.execute(select(Phase).where(Phase.id == workout.phase_id)) phase = result.scalar_one_or_none() return templates.TemplateResponse(request, "workout_detail.html", { "user": user, "workout": workout, "sets": sets, "phase": phase, }) @router.post("/workouts/{workout_id}/add-set") async def add_set( request: Request, workout_id: int, user: User = Depends(get_current_user), exercise: str = Form(), set_number: int = Form(), reps: int = Form(default=None), weight: float = Form(default=None), rpe: float = Form(default=None), notes: str = Form(default=""), ): async with async_session() as session: result = await session.execute( select(Workout).where( Workout.id == workout_id, Workout.user_id == user.id, ) ) workout = result.scalar_one_or_none() if not workout: return RedirectResponse(url="/workouts", status_code=303) ws = WorkoutSet( workout_id=workout_id, exercise=exercise, set_number=set_number, reps=reps, weight=weight, rpe=rpe, notes=notes, ) session.add(ws) await session.commit() return RedirectResponse(url=f"/workouts/{workout_id}", status_code=303) @router.post("/workouts/{workout_id}/complete") async def complete_workout( request: Request, workout_id: int, user: User = Depends(get_current_user), ): async with async_session() as session: result = await session.execute( select(Workout).where( Workout.id == workout_id, Workout.user_id == user.id, ) ) workout = result.scalar_one_or_none() if workout: workout.status = "complete" await session.commit() if not workout: return RedirectResponse(url="/workouts", status_code=303) result = await session.execute( select(WorkoutSet) .where(WorkoutSet.workout_id == workout_id) .order_by(WorkoutSet.exercise, WorkoutSet.set_number) ) sets = result.scalars().all() phase = None if workout.phase_id: result = await session.execute(select(Phase).where(Phase.id == workout.phase_id)) phase = result.scalar_one_or_none() return templates.TemplateResponse(request, "workout_detail.html", { "user": user, "workout": workout, "sets": sets, "phase": phase, })