"""Export service for generating CSV-ready workout history data. Queries workout logs joined with sessions, days, and exercises to produce flat rows suitable for CSV export. """ from datetime import date import structlog from sqlmodel import Session, select from app.models.exercise import Exercise from app.models.workout_log import WorkoutLog from app.models.workout_session import WorkoutSession logger = structlog.get_logger(__name__) class ExportService: """Builds export-ready workout history rows. Args: session: An active SQLModel Session. """ def __init__(self, session: Session) -> None: self._session = session def get_export_rows( self, user_id: int, start_date: date, end_date: date, ) -> list[dict]: """Get flat workout log rows for CSV export. Args: user_id: The user whose data to export. start_date: Inclusive start of date range. end_date: Inclusive end of date range. Returns: List of dicts with keys: date, workout_type, exercise, set_number, reps, weight, felt_easy. """ sessions = self._session.exec( select(WorkoutSession) .where( WorkoutSession.user_id == user_id, WorkoutSession.date >= start_date, WorkoutSession.date <= end_date, ) .order_by(WorkoutSession.date.asc()) ).all() if not sessions: return [] # Pre-load exercises for name lookup exercises = self._session.exec(select(Exercise)).all() exercise_map = {e.id: e for e in exercises} rows = [] for ws in sessions: logs = self._session.exec( select(WorkoutLog) .where(WorkoutLog.session_id == ws.id) .order_by(WorkoutLog.exercise_id, WorkoutLog.set_number) ).all() for log_entry in logs: exercise = exercise_map.get(log_entry.exercise_id) rows.append({ "date": ws.date.isoformat(), "workout_type": exercise.workout_day if exercise else "Unknown", "exercise": exercise.name if exercise else "Unknown", "set_number": log_entry.set_number, "reps": log_entry.reps_completed, "weight": log_entry.weight_used, "felt_easy": "Yes" if log_entry.felt_easy else "No", }) return rows