import uuid from datetime import date from fastapi import APIRouter, Depends from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.core.deps import get_db_session, require_study_member from app.models.milestone import Milestone from app.models.task import Task from app.schemas.progress import StudyProgressRead router = APIRouter() @router.get("/progress", response_model=StudyProgressRead, dependencies=[Depends(require_study_member())]) async def get_progress( study_id: uuid.UUID, db: AsyncSession = Depends(get_db_session), ) -> StudyProgressRead: # Milestones milestone_total_stmt = select(func.count()).select_from(Milestone).where(Milestone.study_id == study_id) milestone_done_stmt = select(func.count()).select_from(Milestone).where( Milestone.study_id == study_id, Milestone.status == "DONE" ) task_total_stmt = select(func.count()).select_from(Task).where(Task.study_id == study_id) task_done_stmt = select(func.count()).select_from(Task).where(Task.study_id == study_id, Task.status == "DONE") task_overdue_stmt = select(func.count()).select_from(Task).where( Task.study_id == study_id, Task.due_date < date.today(), Task.status != "DONE", ) milestone_total = (await db.execute(milestone_total_stmt)).scalar_one() milestone_done = (await db.execute(milestone_done_stmt)).scalar_one() task_total = (await db.execute(task_total_stmt)).scalar_one() task_done = (await db.execute(task_done_stmt)).scalar_one() task_overdue = (await db.execute(task_overdue_stmt)).scalar_one() total_items = milestone_total + task_total done_items = milestone_done + task_done completion_rate = float(done_items / total_items) if total_items else 0.0 return StudyProgressRead( milestones_total=milestone_total, milestones_done=milestone_done, tasks_total=task_total, tasks_done=task_done, tasks_overdue=task_overdue, completion_rate=completion_rate, )