"""Exercise browser routes with HTMX search/filter support. All filtering is done via HTMX partial responses -- no JSON APIs. """ import structlog from fastapi import APIRouter, Depends, Query, 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.exercise_service import ExerciseService from app.utils.auth import require_active_profile logger = structlog.get_logger(__name__) router = APIRouter(prefix="/exercises", tags=["exercises"]) @router.get("", response_class=HTMLResponse) async def exercise_browser( request: Request, session: Session = Depends(get_db_session), profile: User = Depends(require_active_profile), ): """Render the exercise browser page with all exercises.""" exercise_service = ExerciseService(session) exercises = exercise_service.list_exercises() workout_days = exercise_service.list_workout_days() # Collect unique muscle groups for the filter dropdown muscle_groups = sorted(set(ex.muscle_group for ex in exercises)) templates = request.app.state.templates return templates.TemplateResponse("pages/exercise_browser.html", { "request": request, "exercises": exercises, "workout_days": workout_days, "muscle_groups": muscle_groups, }) @router.get("/search", response_class=HTMLResponse) async def exercise_search( request: Request, session: Session = Depends(get_db_session), profile: User = Depends(require_active_profile), workout_day: str = Query(default="", alias="workout_day"), muscle_group: str = Query(default="", alias="muscle_group"), ): """Return filtered exercise list as an HTMX partial.""" exercise_service = ExerciseService(session) exercises = exercise_service.list_exercises( workout_day=workout_day or None, muscle_group=muscle_group or None, ) templates = request.app.state.templates return templates.TemplateResponse("partials/exercise_list.html", { "request": request, "exercises": exercises, })