from typing import Optional, List, Annotated
from pydantic import BaseModel, Field, ConfigDict, field_validator, BeforeValidator
from datetime import date, time, datetime
from utils.utils import AppointmentType, AppointmentStatus

StrId = Annotated[str, BeforeValidator(str)]


class AppointmentBase(BaseModel):
    patient_id: str = Field(..., max_length=36)
    doctor_id: str = Field(..., max_length=36)
    department_id: Optional[str] = Field(None, max_length=36)
    appointment_date: date
    appointment_time: time
    duration_minutes: int = Field(30, ge=1)
    appointment_type: AppointmentType
    status: AppointmentStatus
    reason: Optional[str] = None
    notes: Optional[str] = None

    @field_validator("appointment_date")
    @classmethod
    def validate_date_not_past(cls, v):
        if v and v < date.today():
            raise ValueError("Appointment date cannot be in the past")
        return v


class AppointmentCreate(AppointmentBase):
    pass


class AppointmentUpdate(BaseModel):
    patient_id: Optional[str] = Field(None, max_length=36)
    doctor_id: Optional[str] = Field(None, max_length=36)
    department_id: Optional[str] = Field(None, max_length=36)
    appointment_date: Optional[date] = None
    appointment_time: Optional[time] = None
    duration_minutes: Optional[int] = Field(None, ge=1)
    appointment_type: Optional[AppointmentType] = None
    status: Optional[AppointmentStatus] = None
    reason: Optional[str] = None
    notes: Optional[str] = None

    @field_validator("appointment_date")
    @classmethod
    def validate_date_not_past(cls, v):
        if v and v < date.today():
            raise ValueError("Appointment date cannot be in the past")
        return v


class AppointmentResponse(BaseModel):
    id: StrId
    patient_id: StrId
    doctor_id: StrId
    department_id: Optional[StrId] = None
    appointment_date: date
    appointment_time: time
    duration_minutes: int
    appointment_type: AppointmentType
    status: AppointmentStatus
    reason: Optional[str] = None
    notes: Optional[str] = None
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class PatientSummary(BaseModel):
    id: StrId
    first_name: str
    last_name: str
    phone: Optional[str] = None

    model_config = ConfigDict(from_attributes=True)


class DoctorSummary(BaseModel):
    id: StrId
    first_name: str
    last_name: str

    model_config = ConfigDict(from_attributes=True)


class DepartmentSummary(BaseModel):
    id: StrId
    name: str

    model_config = ConfigDict(from_attributes=True)


class AppointmentDetailResponse(BaseModel):
    id: StrId
    patient_id: StrId
    doctor_id: StrId
    department_id: Optional[StrId] = None
    appointment_date: date
    appointment_time: time
    duration_minutes: int
    appointment_type: AppointmentType
    status: AppointmentStatus
    reason: Optional[str] = None
    notes: Optional[str] = None
    created_at: datetime
    updated_at: datetime
    patient: PatientSummary
    doctor: DoctorSummary
    department: Optional[DepartmentSummary] = None

    model_config = ConfigDict(from_attributes=True)


class PaginatedAppointmentResponse(BaseModel):
    items: List[AppointmentResponse]
    total: int
    limit: int
    offset: int

    model_config = ConfigDict(from_attributes=True)