from typing import Literal from pydantic import BaseModel, Field from uuid import UUID from datetime import datetime, date, time BookingStatus = Literal["pending", "confirmed", "cancelled", "completed", "no_show"] class SlotCreate(BaseModel): date: date start_time: time end_time: time class WeeklyScheduleCreate(BaseModel): day_of_week: int = Field(ge=0, le=6, description="0=Monday, 6=Sunday") start_time: time end_time: time slot_duration_minutes: int = Field(ge=15, le=480, default=60) class WeeklyScheduleOut(BaseModel): id: UUID day_of_week: int start_time: time end_time: time slot_duration_minutes: int is_active: bool class GenerateSlotsRequest(BaseModel): from_date: date to_date: date = Field(description="Max 90 days from from_date") class SlotOut(BaseModel): id: UUID date: date start_time: time end_time: time is_blocked: bool block_reason: str | None = None is_booked: bool = False class UpdateSlotRequest(BaseModel): is_blocked: bool block_reason: str | None = None class BlockedDateCreate(BaseModel): date: date reason: str | None = None class BlockedDateOut(BaseModel): id: UUID date: date reason: str | None = None class BookingCreate(BaseModel): slot_id: UUID service_note: str | None = Field(None, max_length=500) # Guest fields — required when not authenticated guest_name: str | None = Field(None, max_length=100) guest_email: str | None = None guest_phone: str | None = None class BookingOut(BaseModel): id: UUID user_id: UUID | None = None slot_id: UUID slot_date: date slot_start: str # "HH:MM" slot_end: str # "HH:MM" service_note: str | None = None # Resolved client info (from profile or guest fields) client_name: str | None = None client_email: str | None = None client_phone: str | None = None status: str amount_paid: float | None = None stripe_payment_intent_id: str | None = None admin_notes: str | None = None created_at: datetime updated_at: datetime class BookingCheckoutResponse(BaseModel): booking_id: UUID client_secret: str amount: float class UpdateBookingStatus(BaseModel): status: BookingStatus admin_notes: str | None = None