from datetime import datetime, time, timedelta from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, status from sqlmodel.ext.asyncio.session import AsyncSession from app.database import get_session from app.crud import get_sessions, end_sleep_session from app.schemas import ( SessionListResponse, SleepSessionUpdate, SleepSessionRead, SleepSessionCreate, ) router = APIRouter(prefix="/api/sessions", tags=["sessions"]) @router.post("", response_model=SleepSessionRead, status_code=status.HTTP_201_CREATED) async def create_session( payload: SleepSessionCreate, session: AsyncSession = Depends(get_session) ): from app.crud import get_active_session, create_sleep_session active = await get_active_session(session) if active: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="An active sleep session is already open.", ) return await create_sleep_session(session, payload.start_time) @router.get("/active") async def read_active_session(session: AsyncSession = Depends(get_session)): from app.crud import get_active_session active = await get_active_session(session) return await get_active_session(session) @router.get("", response_model=SessionListResponse) async def list_sessions( from_date: Optional[datetime] = None, to_date: Optional[datetime] = None, limit: int = 200, session: AsyncSession = Depends(get_session), ): sessions, total = await get_sessions(session, from_date, to_date, limit) return {"sessions": sessions, "total": total} @router.patch("/{session_id}/end", response_model=None) async def end_session_endpoint( session_id: int, payload: SleepSessionUpdate, session: AsyncSession = Depends(get_session), ): if not payload.end_time: raise HTTPException( status_code=400, detail="end_time is required to end a session." ) result = await end_sleep_session(session, session_id, payload.end_time) if result is None: raise HTTPException(status_code=404, detail="Session not found.") if result is False: raise HTTPException(status_code=409, detail="Session has already ended.") if result == "invalid": raise HTTPException( status_code=400, detail="end_time cannot be before start_time." ) return result @router.delete("/{session_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_session_endpoint( session_id: int, session: AsyncSession = Depends(get_session) ): from app.crud import delete_session success = await delete_session(session, session_id) if not success: raise HTTPException(status_code=404, detail="Session not found.") return None @router.patch("/{session_id}", response_model=SleepSessionRead) async def update_session_endpoint( session_id: int, payload: SleepSessionUpdate, session: AsyncSession = Depends(get_session), ): from app.crud import update_session updated = await update_session( session, session_id, payload.model_dump(exclude_unset=True) ) if not updated: raise HTTPException(status_code=404, detail="Session not found.") return updated