from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from typing import Optional, List from datetime import date from app.database import get_db from app.models.calendar_event import CalendarEvent from app.schemas.calendar_event import CalendarEventCreate, CalendarEventUpdate, CalendarEventResponse from app.routers.auth import get_current_session from app.models.settings import Settings router = APIRouter() @router.get("/", response_model=List[CalendarEventResponse]) async def get_events( start: Optional[date] = Query(None), end: Optional[date] = Query(None), db: AsyncSession = Depends(get_db), current_user: Settings = Depends(get_current_session) ): """Get all calendar events with optional date range filtering.""" query = select(CalendarEvent) if start: query = query.where(CalendarEvent.end_datetime >= start) if end: query = query.where(CalendarEvent.start_datetime <= end) query = query.order_by(CalendarEvent.start_datetime.asc()) result = await db.execute(query) events = result.scalars().all() return events @router.post("/", response_model=CalendarEventResponse, status_code=201) async def create_event( event: CalendarEventCreate, db: AsyncSession = Depends(get_db), current_user: Settings = Depends(get_current_session) ): """Create a new calendar event.""" if event.end_datetime < event.start_datetime: raise HTTPException(status_code=400, detail="End datetime must be after start datetime") new_event = CalendarEvent(**event.model_dump()) db.add(new_event) await db.commit() await db.refresh(new_event) return new_event @router.get("/{event_id}", response_model=CalendarEventResponse) async def get_event( event_id: int, db: AsyncSession = Depends(get_db), current_user: Settings = Depends(get_current_session) ): """Get a specific calendar event by ID.""" result = await db.execute(select(CalendarEvent).where(CalendarEvent.id == event_id)) event = result.scalar_one_or_none() if not event: raise HTTPException(status_code=404, detail="Calendar event not found") return event @router.put("/{event_id}", response_model=CalendarEventResponse) async def update_event( event_id: int, event_update: CalendarEventUpdate, db: AsyncSession = Depends(get_db), current_user: Settings = Depends(get_current_session) ): """Update a calendar event.""" result = await db.execute(select(CalendarEvent).where(CalendarEvent.id == event_id)) event = result.scalar_one_or_none() if not event: raise HTTPException(status_code=404, detail="Calendar event not found") update_data = event_update.model_dump(exclude_unset=True) # Validate datetime order if both are being updated start = update_data.get("start_datetime", event.start_datetime) end = update_data.get("end_datetime", event.end_datetime) if end < start: raise HTTPException(status_code=400, detail="End datetime must be after start datetime") for key, value in update_data.items(): setattr(event, key, value) await db.commit() await db.refresh(event) return event @router.delete("/{event_id}", status_code=204) async def delete_event( event_id: int, db: AsyncSession = Depends(get_db), current_user: Settings = Depends(get_current_session) ): """Delete a calendar event.""" result = await db.execute(select(CalendarEvent).where(CalendarEvent.id == event_id)) event = result.scalar_one_or_none() if not event: raise HTTPException(status_code=404, detail="Calendar event not found") await db.delete(event) await db.commit() return None