"""Canonical warehouse schema.

Dataclasses for all domain entities.  These are provider-agnostic —
downstream code depends on these types, not on Fitbit or fddb
response shapes.

Each entity carries provenance (source, fetched_at) and uses natural
keys for cross-references.
"""

from dataclasses import dataclass


# -- Provenance mixin --------------------------------------------------------


@dataclass(frozen=True)
class _Provenance:
    source: str
    fetched_at: str


# -- Vitals snapshots --------------------------------------------------------


@dataclass(frozen=True)
class HeartRateSample(_Provenance):
    """Individual heart rate reading at minute resolution."""

    date: str
    time: str
    bpm: int


@dataclass(frozen=True)
class RestingHeartRateSample(_Provenance):
    """Daily resting heart rate."""

    date: str
    bpm: int


@dataclass(frozen=True)
class StepSnapshot(_Provenance):
    """Cumulative step count at observation time."""

    date: str
    observed_at: str
    steps: int


@dataclass(frozen=True)
class CalorieSnapshot(_Provenance):
    """Cumulative calories burned at observation time."""

    date: str
    observed_at: str
    calories: int


@dataclass(frozen=True)
class ActiveMinutesSnapshot(_Provenance):
    """Cumulative active minutes at observation time."""

    date: str
    observed_at: str
    fairly_active: int
    very_active: int


@dataclass(frozen=True)
class ActivityLevelSnapshot(_Provenance):
    """Activity level breakdown at observation time."""

    date: str
    observed_at: str
    sedentary_minutes: int
    lightly_active_minutes: int
    fairly_active_minutes: int
    very_active_minutes: int


@dataclass(frozen=True)
class DistanceSnapshot(_Provenance):
    """Distance, floors, and elevation at observation time."""

    date: str
    observed_at: str
    distance_km: float
    floors: int
    elevation: float


@dataclass(frozen=True)
class GoalSnapshot(_Provenance):
    """Goal targets at observation time."""

    date: str
    observed_at: str
    steps_goal: int
    active_minutes_goal: int


# -- Sleep -------------------------------------------------------------------


@dataclass(frozen=True)
class SleepSession(_Provenance):
    """One sleep period."""

    date: str
    bedtime: str
    wake_time: str
    duration_hours: float
    score: int
    is_main: bool


@dataclass(frozen=True)
class SleepStage(_Provenance):
    """Stage within a sleep session.

    Cross-reference: (date, bedtime) → SleepSession.
    """

    date: str
    bedtime: str
    stage: str
    minutes: int


# -- Activity ----------------------------------------------------------------


@dataclass(frozen=True)
class ActivitySession(_Provenance):
    """A logged exercise session."""

    date: str
    start_time: str
    name: str
    calories: int
    duration_min: float
    steps: int


# -- Body --------------------------------------------------------------------


@dataclass(frozen=True)
class BodyMeasurement(_Provenance):
    """Body measurement observation."""

    date: str
    weight_kg: float
    body_fat_pct: float
    bmi: float
    muscle_mass_kg: float
    chest_cm: float
    waist_cm: float
    hips_cm: float
    bicep_cm: float
    thigh_cm: float


# -- Water -------------------------------------------------------------------


@dataclass(frozen=True)
class WaterIntake(_Provenance):
    """Water intake observation."""

    date: str
    amount_ml: int


# -- Nutrition ---------------------------------------------------------------


@dataclass(frozen=True)
class NutritionDay(_Provenance):
    """Daily calorie and macro totals."""

    date: str
    calories_consumed: int
    calories_target: int
    protein_g: float
    carbs_g: float
    fat_g: float


@dataclass(frozen=True)
class Meal(_Provenance):
    """A meal within a day.

    Identified by (date, meal_name).
    """

    date: str
    meal_name: str
    calories: int
    protein_g: float
    carbs_g: float
    fat_g: float


@dataclass(frozen=True)
class MealItem(_Provenance):
    """Individual food item within a meal.

    Cross-reference: (date, meal_name) → Meal.
    """

    date: str
    meal_name: str
    item_name: str


# -- Registry ----------------------------------------------------------------

ALL_ENTITIES = {
    "heart-rate-sample": HeartRateSample,
    "resting-heart-rate-sample": RestingHeartRateSample,
    "step-snapshot": StepSnapshot,
    "calorie-snapshot": CalorieSnapshot,
    "active-minutes-snapshot": ActiveMinutesSnapshot,
    "activity-level-snapshot": ActivityLevelSnapshot,
    "distance-snapshot": DistanceSnapshot,
    "goal-snapshot": GoalSnapshot,
    "sleep-session": SleepSession,
    "sleep-stage": SleepStage,
    "activity-session": ActivitySession,
    "body-measurement": BodyMeasurement,
    "nutrition-day": NutritionDay,
    "meal": Meal,
    "meal-item": MealItem,
    "water-intake": WaterIntake,
}

NATURAL_KEYS: dict[str, tuple[str, ...]] = {
    "heart-rate-sample": ("date", "time"),
    "resting-heart-rate-sample": ("date",),
    "step-snapshot": ("date",),
    "calorie-snapshot": ("date",),
    "active-minutes-snapshot": ("date",),
    "activity-level-snapshot": ("date",),
    "distance-snapshot": ("date",),
    "goal-snapshot": ("date",),
    "sleep-session": ("date", "bedtime"),
    "sleep-stage": ("date", "bedtime", "stage"),
    "activity-session": ("date", "start_time", "name"),
    "body-measurement": ("date",),
    "nutrition-day": ("date",),
    "meal": ("date", "meal_name"),
    "meal-item": ("date", "meal_name", "item_name"),
}
