from __future__ import annotations import uuid from datetime import datetime from typing import Any, Generic, TypeVar from pydantic import BaseModel, ConfigDict, Field T = TypeVar("T") class BaseSchema(BaseModel): """Base schema with common configuration.""" model_config = ConfigDict( from_attributes=True, populate_by_name=True, str_strip_whitespace=True, ) class PaginationParams(BaseModel): """Pagination query parameters.""" page: int = Field(default=1, ge=1, description="Page number") page_size: int = Field(default=20, ge=1, le=100, description="Items per page") @property def offset(self) -> int: return (self.page - 1) * self.page_size class PaginatedResponse(BaseSchema, Generic[T]): """Paginated response wrapper.""" items: list[T] total: int page: int page_size: int total_pages: int @classmethod def create(cls, items: list[T], total: int, page: int, page_size: int) -> PaginatedResponse[T]: total_pages = (total + page_size - 1) // page_size if page_size > 0 else 0 return cls( items=items, total=total, page=page, page_size=page_size, total_pages=total_pages, ) class ErrorResponse(BaseSchema): """Standard error response.""" detail: str error_code: str | None = None errors: list[dict[str, Any]] | None = None timestamp: datetime = Field(default_factory=datetime.utcnow) class SuccessResponse(BaseSchema): """Standard success response.""" message: str data: dict[str, Any] | None = None class HealthResponse(BaseSchema): """Health check response.""" status: str version: str environment: str database: str redis: str timestamp: datetime = Field(default_factory=datetime.utcnow) class IDResponse(BaseSchema): """Response containing just an ID.""" id: uuid.UUID