from datetime import date, datetime from pydantic import BaseModel, ConfigDict, EmailStr, Field, model_validator from .models import EntryKind class Register(BaseModel): email: EmailStr password: str = Field(min_length=12, max_length=128) class Token(BaseModel): access_token: str token_type: str = "bearer" class ProfileIn(BaseModel): display_name: str | None = Field(None, max_length=80) birth_date: date | None = None height_cm: float | None = Field(None, ge=80, le=250) objective: str | None = Field(None, max_length=120) health_context: str | None = Field(None, max_length=1000) consent_health_data: bool = False class ProfileOut(ProfileIn): user_id: str updated_at: datetime model_config = ConfigDict(from_attributes=True) RANGES = { EntryKind.weight: (20, 500), EntryKind.glucose: (20, 600), EntryKind.water: (0, 15000), EntryKind.activity: (0, 1440), EntryKind.sleep: (0, 24), EntryKind.mood: (1, 5), EntryKind.meal: (0, 10000), } class EntryIn(BaseModel): kind: EntryKind value: float unit: str = Field(min_length=1, max_length=24) note: str | None = Field(None, max_length=500) recorded_at: datetime | None = None @model_validator(mode="after") def sensible_range(self): if self.kind == EntryKind.glucose: glucose_ranges = {"mg/dL": (20, 600), "mmol/L": (1.1, 33.3)} if self.unit not in glucose_ranges: raise ValueError("glucose unit must be mg/dL or mmol/L") low, high = glucose_ranges[self.unit] else: low, high = RANGES[self.kind] if not low <= self.value <= high: raise ValueError(f"value must be between {low} and {high} for {self.kind.value}") return self class EntryOut(EntryIn): id: str user_id: str recorded_at: datetime created_at: datetime model_config = ConfigDict(from_attributes=True)