"""Appointment DTOs — Phase 13.1.""" from __future__ import annotations from datetime import datetime, time from uuid import UUID from pydantic import BaseModel, ConfigDict, Field from app.models.types import AppointmentStatus, DayOfWeek, LifecycleStatus from app.schemas.common import ORMBase _FORBID = ConfigDict(extra="forbid") class ScheduleCreate(BaseModel): model_config = _FORBID clinic_id: UUID doctor_id: UUID department_id: UUID | None = None code: str = Field(max_length=50) name: str = Field(max_length=255) day_of_week: DayOfWeek start_time: time end_time: time slot_duration_minutes: int = Field(default=30, ge=5, le=480) is_active: bool = True metadata_json: dict | None = None class ScheduleRead(ORMBase): id: UUID tenant_id: UUID clinic_id: UUID doctor_id: UUID department_id: UUID | None code: str name: str day_of_week: DayOfWeek start_time: time end_time: time slot_duration_minutes: int is_active: bool metadata_json: dict | None is_deleted: bool created_at: datetime updated_at: datetime class AvailabilityWindowCreate(BaseModel): model_config = _FORBID clinic_id: UUID doctor_id: UUID code: str = Field(max_length=50) starts_at: datetime ends_at: datetime is_bookable: bool = True metadata_json: dict | None = None class AvailabilityWindowRead(ORMBase): id: UUID tenant_id: UUID clinic_id: UUID doctor_id: UUID code: str starts_at: datetime ends_at: datetime is_bookable: bool metadata_json: dict | None is_deleted: bool created_at: datetime updated_at: datetime class AppointmentTypeCreate(BaseModel): model_config = _FORBID clinic_id: UUID code: str = Field(max_length=50) name: str = Field(max_length=255) description: str | None = None default_duration_minutes: int = Field(default=30, ge=5, le=480) status: LifecycleStatus = LifecycleStatus.ACTIVE class AppointmentTypeRead(ORMBase): id: UUID tenant_id: UUID clinic_id: UUID code: str name: str description: str | None default_duration_minutes: int status: LifecycleStatus is_deleted: bool created_at: datetime updated_at: datetime class AppointmentCreate(BaseModel): model_config = _FORBID clinic_id: UUID doctor_id: UUID patient_id: UUID department_id: UUID | None = None appointment_type_id: UUID | None = None code: str = Field(max_length=50) scheduled_start: datetime scheduled_end: datetime notes: str | None = None metadata_json: dict | None = None class AppointmentReschedule(BaseModel): model_config = _FORBID scheduled_start: datetime scheduled_end: datetime version: int = Field(ge=1) reason: str | None = Field(default=None, max_length=500) class AppointmentLifecycleRequest(BaseModel): model_config = _FORBID version: int = Field(ge=1) reason: str | None = Field(default=None, max_length=500) class AppointmentRead(ORMBase): id: UUID tenant_id: UUID clinic_id: UUID doctor_id: UUID patient_id: UUID department_id: UUID | None appointment_type_id: UUID | None code: str status: AppointmentStatus scheduled_start: datetime scheduled_end: datetime notes: str | None status_reason: str | None status_changed_at: datetime | None reminder_scheduled: bool metadata_json: dict | None version: int is_deleted: bool created_at: datetime updated_at: datetime class AppointmentListResponse(BaseModel): items: list[AppointmentRead] total: int page: int page_size: int class WaitingListEntryCreate(BaseModel): model_config = _FORBID clinic_id: UUID doctor_id: UUID | None = None patient_id: UUID appointment_type_id: UUID | None = None code: str = Field(max_length=50) preferred_date: str | None = Field(default=None, max_length=32) notes: str | None = None priority: int = Field(default=100, ge=1, le=1000) class WaitingListEntryRead(ORMBase): id: UUID tenant_id: UUID clinic_id: UUID doctor_id: UUID | None patient_id: UUID appointment_type_id: UUID | None code: str preferred_date: str | None notes: str | None priority: int is_deleted: bool created_at: datetime updated_at: datetime