from pydantic import BaseModel, ConfigDict from datetime import datetime from typing import Literal, Optional class RecurrenceRule(BaseModel): """Structured recurrence rule — serialized to/from JSON string in the DB column.""" type: Literal["every_n_days", "weekly", "monthly_nth_weekday", "monthly_date"] # every_n_days interval: Optional[int] = None # weekly / monthly_nth_weekday weekday: Optional[int] = None # 0=Mon … 6=Sun # monthly_nth_weekday week: Optional[int] = None # 1-4 # monthly_date day: Optional[int] = None # 1-31 class CalendarEventCreate(BaseModel): title: str description: Optional[str] = None start_datetime: datetime end_datetime: datetime all_day: bool = False color: Optional[str] = None location_id: Optional[int] = None recurrence_rule: Optional[RecurrenceRule] = None # structured; router serializes to JSON string is_starred: bool = False calendar_id: Optional[int] = None # If None, server assigns default calendar class CalendarEventUpdate(BaseModel): title: Optional[str] = None description: Optional[str] = None start_datetime: Optional[datetime] = None end_datetime: Optional[datetime] = None all_day: Optional[bool] = None color: Optional[str] = None location_id: Optional[int] = None recurrence_rule: Optional[RecurrenceRule] = None # structured; router serializes to JSON string is_starred: Optional[bool] = None calendar_id: Optional[int] = None # Controls which occurrences an edit applies to; absent = non-recurring or whole-series edit_scope: Optional[Literal["this", "this_and_future"]] = None class CalendarEventResponse(BaseModel): id: int title: str description: Optional[str] start_datetime: datetime end_datetime: datetime all_day: bool color: Optional[str] location_id: Optional[int] recurrence_rule: Optional[str] # raw JSON string from DB; frontend parses is_starred: bool calendar_id: int calendar_name: str calendar_color: str is_virtual: bool = False # Recurrence fields parent_event_id: Optional[int] = None is_recurring: bool = False original_start: Optional[datetime] = None created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True)