"""# Summary Appointments route handlers — names must match openapi.yaml operationIds. Notes: ``pet``, ``vet`` and ``treatment`` are foreign keys expanded to full objects on read and normalized from ids on write. The list endpoint supports date-prefix and pet/vet id filters. """ from fastapi import Request, Response from interfaces._common import ( delete_or_404, dump, expand_ref, paginate, read_or_404, svc, ) async def list_appointments( request: Request, limit: int = 20, offset: int = 0, date: str | None = None, vet: int | None = None, pet: int | None = None, ) -> dict: """List appointments (paginated, filterable by date/vet/pet). Args: request (Request): Incoming request. limit (int): Page size. Defaults to 20. offset (int): Items to skip. Defaults to 0. date (str | None): ISO date prefix to match (e.g. ``2025-06-01``). vet (int | None): Filter by embedded vet id. pet (int | None): Filter by embedded pet id. Returns: dict: ``{"total": int, "items": list[Appointment]}``. """ docs = await svc(request, "appointment").search({}) items = [] for d in docs: row = dump(d) if date and not str(row.get("date", "")).startswith(date): continue if vet is not None and (row.get("vet") or {}).get("id") != vet: continue if pet is not None and (row.get("pet") or {}).get("id") != pet: continue items.append(row) return paginate(items, limit, offset) async def create_appointment(request: Request, body: dict, response: Response) -> dict: """Create an appointment; FK fields may be bare ids or expanded objects. Args: request (Request): Incoming request. body (dict): Appointment fields (``id`` ignored; FKs normalized). response (Response): Response object; set to 201 on success. Returns: dict: The created appointment with FKs expanded. Raises: HTTPException: 422 when an FK reference cannot be resolved. """ response.status_code = 201 body.pop("id", None) body["pet"] = await expand_ref(svc(request, "pet"), body.get("pet"), "pet") body["vet"] = await expand_ref(svc(request, "vet"), body.get("vet"), "vet") body["treatment"] = await expand_ref( svc(request, "treatment"), body.get("treatment"), "treatment" ) doc = await svc(request, "appointment").create(body) return dump(doc) async def get_appointment(request: Request, id: int) -> dict: """Fetch one appointment by id. Args: request (Request): Incoming request. id (int): Appointment identifier. Returns: dict: The appointment document. Raises: HTTPException: 404 when the appointment does not exist. """ return dump(await read_or_404(svc(request, "appointment"), id, "appointment")) async def update_appointment(request: Request, id: int, body: dict) -> dict: """Replace an appointment by id; FK fields may be ids or objects. Args: request (Request): Incoming request. id (int): Appointment identifier. body (dict): Full replacement payload. Returns: dict: The updated appointment with FKs expanded. Raises: HTTPException: 404 when the appointment does not exist; 422 on bad FKs. """ await read_or_404(svc(request, "appointment"), id, "appointment") body.pop("id", None) body["pet"] = await expand_ref(svc(request, "pet"), body.get("pet"), "pet") body["vet"] = await expand_ref(svc(request, "vet"), body.get("vet"), "vet") body["treatment"] = await expand_ref( svc(request, "treatment"), body.get("treatment"), "treatment" ) doc = await svc(request, "appointment").update(id, body) return dump(doc) async def delete_appointment(request: Request, id: int, response: Response) -> None: """Delete an appointment by id. Args: request (Request): Incoming request. id (int): Appointment identifier. response (Response): Response object; set to 204 on success. Raises: HTTPException: 404 when the appointment does not exist. """ await delete_or_404(svc(request, "appointment"), id, "appointment") response.status_code = 204