from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from sqlalchemy.orm import selectinload from app.dependencies import get_db, get_current_user from app.models.schedule import ScheduleTemplate, ScheduleBlock from app.models.user import User from app.schemas.schedule import ( ScheduleTemplateCreate, ScheduleTemplateOut, ScheduleTemplateUpdate, ScheduleBlockCreate, ScheduleBlockOut, ) router = APIRouter(prefix="/api/schedules", tags=["schedules"]) @router.get("", response_model=list[ScheduleTemplateOut]) async def list_templates( current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(ScheduleTemplate) .where(ScheduleTemplate.user_id == current_user.id) .options(selectinload(ScheduleTemplate.blocks)) .order_by(ScheduleTemplate.name) ) return result.scalars().all() @router.post("", response_model=ScheduleTemplateOut, status_code=status.HTTP_201_CREATED) async def create_template( body: ScheduleTemplateCreate, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): template = ScheduleTemplate( user_id=current_user.id, name=body.name, child_id=body.child_id, is_default=body.is_default, ) db.add(template) await db.flush() # get template.id before adding blocks for block_data in body.blocks: block = ScheduleBlock(template_id=template.id, **block_data.model_dump()) db.add(block) await db.commit() await db.refresh(template) # Re-fetch with blocks loaded result = await db.execute( select(ScheduleTemplate) .where(ScheduleTemplate.id == template.id) .options(selectinload(ScheduleTemplate.blocks)) ) return result.scalar_one() @router.get("/{template_id}", response_model=ScheduleTemplateOut) async def get_template( template_id: int, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(ScheduleTemplate) .where(ScheduleTemplate.id == template_id, ScheduleTemplate.user_id == current_user.id) .options(selectinload(ScheduleTemplate.blocks)) ) template = result.scalar_one_or_none() if not template: raise HTTPException(status_code=404, detail="Template not found") return template @router.patch("/{template_id}", response_model=ScheduleTemplateOut) async def update_template( template_id: int, body: ScheduleTemplateUpdate, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(ScheduleTemplate) .where(ScheduleTemplate.id == template_id, ScheduleTemplate.user_id == current_user.id) .options(selectinload(ScheduleTemplate.blocks)) ) template = result.scalar_one_or_none() if not template: raise HTTPException(status_code=404, detail="Template not found") for field, value in body.model_dump(exclude_none=True).items(): setattr(template, field, value) await db.commit() await db.refresh(template) return template @router.delete("/{template_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_template( template_id: int, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(ScheduleTemplate) .where(ScheduleTemplate.id == template_id, ScheduleTemplate.user_id == current_user.id) ) template = result.scalar_one_or_none() if not template: raise HTTPException(status_code=404, detail="Template not found") await db.delete(template) await db.commit() # --- Schedule Block sub-routes --- @router.post("/{template_id}/blocks", response_model=ScheduleBlockOut, status_code=status.HTTP_201_CREATED) async def add_block( template_id: int, body: ScheduleBlockCreate, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(ScheduleTemplate) .where(ScheduleTemplate.id == template_id, ScheduleTemplate.user_id == current_user.id) ) if not result.scalar_one_or_none(): raise HTTPException(status_code=404, detail="Template not found") block = ScheduleBlock(template_id=template_id, **body.model_dump()) db.add(block) await db.commit() await db.refresh(block) return block @router.delete("/{template_id}/blocks/{block_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_block( template_id: int, block_id: int, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(ScheduleBlock) .join(ScheduleTemplate) .where( ScheduleBlock.id == block_id, ScheduleBlock.template_id == template_id, ScheduleTemplate.user_id == current_user.id, ) ) block = result.scalar_one_or_none() if not block: raise HTTPException(status_code=404, detail="Block not found") await db.delete(block) await db.commit()