"""Timetable/schedule models for Medelement MIS API."""

from typing import Optional, Union

from pydantic import Field, RootModel

from .base import MedelementBaseModel


class GetTimetableRequest(MedelementBaseModel):
    """Request model for getting specialist timetable.

    GET https://api3.medelement.com/v1/timetable/get_timetable
    """

    date: list[str] = Field(..., description="Array of dates to query")
    specialist_code: int = Field(..., alias="specialistCode")


class TimetableSlot(MedelementBaseModel):
    """Individual time slot in timetable.

    Represents a time period that may or may not be available for booking.
    """

    start: str = Field(..., description="Slot start datetime")
    end: str = Field(..., description="Slot end datetime")
    working: bool = Field(..., description="Whether slot is available for booking")


class ClinicWorkingHours(MedelementBaseModel):
    """Clinic operating hours for a day."""

    start: str = Field(..., description="Clinic opening time")
    end: str = Field(..., description="Clinic closing time")


class TimeOff(MedelementBaseModel):
    """Time off period within working hours.

    Represents breaks, meetings, or other unavailable periods.
    """

    start: str
    end: str


class SpecialistWorkingHours(MedelementBaseModel):
    """Specialist working hours for a day.

    Includes work start/end times, lunch break, and additional time off periods.
    """

    start: str = Field(..., description="Work start time")
    end: str = Field(..., description="Work end time")
    start_lunch: Optional[str] = Field(None, description="Lunch break start")
    end_lunch: Optional[str] = Field(None, description="Lunch break end")
    time_off: list[TimeOff] = Field(
        default_factory=list, description="Additional time off periods"
    )


# Union type: specialist working hours can be an object or "day off" string
SpecialistSchedule = Union[SpecialistWorkingHours, str]


class DaySchedule(MedelementBaseModel):
    """Complete schedule for a single day.

    Contains timetable slots, clinic hours, and specialist availability.
    specialistWorkingHours can be "day off" string if specialist is not working.
    """

    timetable: list[TimetableSlot] = Field(default_factory=list)
    clinic_working_hours: ClinicWorkingHours = Field(..., alias="clinicWorkingHours")
    specialist_working_hours: SpecialistSchedule = Field(..., alias="specialistWorkingHours")

    @property
    def is_day_off(self) -> bool:
        """Check if this is a day off for the specialist."""
        return isinstance(self.specialist_working_hours, str)

    @property
    def available_slots(self) -> list[TimetableSlot]:
        """Get only working/available slots."""
        return [slot for slot in self.timetable if slot.working]


class TimetableResponse(RootModel[dict[str, DaySchedule]]):
    """Timetable response - dictionary keyed by date strings.

    Example: {"14.10.2024": {day_schedule}, "15.10.2024": {day_schedule}}
    """

    def __iter__(self):
        return iter(self.root)

    def __getitem__(self, date: str) -> DaySchedule:
        return self.root[date]

    def __len__(self) -> int:
        return len(self.root)

    def keys(self):
        return self.root.keys()

    def values(self):
        return self.root.values()

    def items(self):
        return self.root.items()

    def get_schedule(self, date: str) -> Optional[DaySchedule]:
        """Get schedule for a specific date, or None if not found."""
        return self.root.get(date)
