import enum import uuid from datetime import date, datetime, timezone from sqlalchemy import Boolean, Date, DateTime, Enum, Float, ForeignKey, Integer, String, Text from sqlalchemy.orm import Mapped, mapped_column, relationship from .db import Base def now() -> datetime: return datetime.now(timezone.utc) class EntryKind(str, enum.Enum): weight = "weight" glucose = "glucose" water = "water" activity = "activity" sleep = "sleep" mood = "mood" meal = "meal" class User(Base): __tablename__ = "users" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) email: Mapped[str] = mapped_column(String(320), unique=True, index=True) password_hash: Mapped[str] = mapped_column(String(255)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=now) profile: Mapped["Profile | None"] = relationship(back_populates="user", cascade="all, delete-orphan") entries: Mapped[list["Entry"]] = relationship(back_populates="user", cascade="all, delete-orphan") class Profile(Base): __tablename__ = "profiles" user_id: Mapped[str] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), primary_key=True) display_name: Mapped[str | None] = mapped_column(String(80)) birth_date: Mapped[date | None] = mapped_column(Date) height_cm: Mapped[float | None] = mapped_column(Float) objective: Mapped[str | None] = mapped_column(String(120)) health_context: Mapped[str | None] = mapped_column(Text) consent_health_data: Mapped[bool] = mapped_column(Boolean, default=False) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=now, onupdate=now) user: Mapped[User] = relationship(back_populates="profile") class Entry(Base): __tablename__ = "entries" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) user_id: Mapped[str] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) kind: Mapped[EntryKind] = mapped_column(Enum(EntryKind)) value: Mapped[float] = mapped_column(Float) unit: Mapped[str] = mapped_column(String(24)) note: Mapped[str | None] = mapped_column(String(500)) recorded_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=now, index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=now) user: Mapped[User] = relationship(back_populates="entries")