"""API schemas (Pydantic) for the Swedish calendar endpoint (röda dagar / klämdagar). Wire format for `GET /api/calendar/days` — serves both §3.4 (shading the Kalender page) and §3.8 (the per-year red-days list in Settings) from one endpoint. Kept separate from the service's dataclasses so the wire format can evolve independently. """ from __future__ import annotations from datetime import date from pydantic import BaseModel, Field from app.services.calendar_service import CalendarDay, CalendarWindow, DayType class CalendarDayResponse(BaseModel): date: date name: str | None day_type: DayType is_override: bool override_is_working_day: bool | None is_free: bool @classmethod def from_domain(cls, day: CalendarDay) -> "CalendarDayResponse": return cls( date=day.date, name=day.name, day_type=day.day_type, is_override=day.is_override, override_is_working_day=day.override_is_working_day, is_free=day.is_free, ) class CalendarDaysResponse(BaseModel): """A `years`-year window of calendar days (max `MAX_WINDOW_YEARS`, currently 4), plus the full cached range so the UI can bound its pagination controls. """ start_year: int end_year: int min_year: int | None = Field( default=None, description="First year covered by the cache, or None if the cache is missing.", ) max_year: int | None = Field( default=None, description="Last year covered by the cache, or None if the cache is missing." ) days: list[CalendarDayResponse] @classmethod def from_domain(cls, window: CalendarWindow) -> "CalendarDaysResponse": return cls( start_year=window.start_year, end_year=window.end_year, min_year=window.min_year, max_year=window.max_year, days=[CalendarDayResponse.from_domain(d) for d in window.days], )