"""Workout logging routes for inline set tracking. Handles creating, editing, and deleting individual set logs. All responses are HTMX partials that update in place. """ from datetime import date import structlog from fastapi import APIRouter, Depends, Request from fastapi.responses import HTMLResponse from sqlmodel import Session from app.database import get_db_session from app.models.user import User from app.services.log_service import LogService from app.services.workout_session_service import WorkoutSessionService from app.utils.auth import require_active_profile, get_active_profile_id logger = structlog.get_logger(__name__) router = APIRouter(prefix="/log", tags=["logging"]) @router.post("", response_class=HTMLResponse) async def log_set( request: Request, session: Session = Depends(get_db_session), profile: User = Depends(require_active_profile), ): """Log a single set for an exercise. Creates the workout session if it doesn't exist yet (auto-create). Returns the updated log entries partial for this exercise. """ form = await request.form() exercise_id = int(form.get("exercise_id", 0)) workout_day_id = int(form.get("workout_day_id", 0)) set_number = int(form.get("set_number", 1)) reps = int(form.get("reps", 0)) weight = form.get("weight", "") felt_easy = form.get("felt_easy") == "on" # Get or create today's session ws_service = WorkoutSessionService(session) ws = ws_service.get_or_create_session( user_id=profile.id, workout_day_id=workout_day_id, session_date=date.today(), ) # Create the log entry log_service = LogService(session) log_service.create_log( session_id=ws.id, exercise_id=exercise_id, set_number=set_number, reps_completed=reps, weight_used=weight, felt_easy=felt_easy, ) # Return updated logs for this exercise logs = log_service.list_logs_for_exercise(ws.id, exercise_id) next_set = len(logs) + 1 templates = request.app.state.templates return templates.TemplateResponse("partials/log_entry.html", { "request": request, "logs": logs, "exercise_id": exercise_id, "workout_day_id": workout_day_id, "next_set": next_set, "session_id": ws.id, }) @router.post("/{log_id}/edit", response_class=HTMLResponse) async def edit_log( log_id: int, request: Request, session: Session = Depends(get_db_session), profile: User = Depends(require_active_profile), ): """Edit an existing log entry.""" form = await request.form() log_service = LogService(session) log_service.update_log( log_id, reps_completed=int(form.get("reps", 0)), weight_used=form.get("weight", ""), felt_easy=form.get("felt_easy") == "on", notes=form.get("notes"), ) log = log_service.get_log_by_id(log_id) logs = log_service.list_logs_for_exercise(log.session_id, log.exercise_id) next_set = len(logs) + 1 templates = request.app.state.templates return templates.TemplateResponse("partials/log_entry.html", { "request": request, "logs": logs, "exercise_id": log.exercise_id, "workout_day_id": 0, "next_set": next_set, "session_id": log.session_id, }) @router.post("/{log_id}/delete", response_class=HTMLResponse) async def delete_log( log_id: int, request: Request, session: Session = Depends(get_db_session), profile: User = Depends(require_active_profile), ): """Delete a log entry.""" log_service = LogService(session) log = log_service.get_log_by_id(log_id) if log: exercise_id = log.exercise_id session_id = log.session_id log_service.delete_log(log_id) logs = log_service.list_logs_for_exercise(session_id, exercise_id) next_set = len(logs) + 1 templates = request.app.state.templates return templates.TemplateResponse("partials/log_entry.html", { "request": request, "logs": logs, "exercise_id": exercise_id, "workout_day_id": 0, "next_set": next_set, "session_id": session_id, }) return HTMLResponse("")