"""Fitbit raw-to-canonical transformers.

Each function takes a raw Envelope payload (the Fitbit API JSON) and
returns a list of canonical domain records.  No API calls, no I/O —
pure data transformation.
"""

from byteb4rb1e.homeostat.warehouse.schema import (
    ActiveMinutesSnapshot,
    ActivityLevelSnapshot,
    ActivitySession,
    BodyMeasurement,
    CalorieSnapshot,
    DistanceSnapshot,
    GoalSnapshot,
    HeartRateSample,
    RestingHeartRateSample,
    SleepSession,
    SleepStage,
    StepSnapshot,
)


def transform_heart_rate(
    payload: dict,
    date: str,
    fetched_at: str,
) -> tuple[
    list[HeartRateSample],
    list[RestingHeartRateSample],
]:
    """Transform heart rate data into samples and resting HR.

    Returns two lists: intraday heart-rate samples and
    resting heart-rate samples (at most one per call).
    """
    dataset = (
        payload
        .get("activities-heart-intraday", {})
        .get("dataset", [])
    )
    samples = [
        HeartRateSample(
            source="fitbit",
            fetched_at=fetched_at,
            date=date,
            time=point["time"],
            bpm=point["value"],
        )
        for point in dataset
    ]

    resting: list[RestingHeartRateSample] = []
    activities_heart = payload.get(
        "activities-heart", []
    )
    if activities_heart:
        value = activities_heart[0].get("value", {})
        if isinstance(value, str):
            value = {}
        rhr = value.get("restingHeartRate", 0)
        if rhr:
            resting = [
                RestingHeartRateSample(
                    source="fitbit",
                    fetched_at=fetched_at,
                    date=date,
                    bpm=rhr,
                )
            ]

    return samples, resting


def transform_steps(
    payload: dict,
    date: str,
    fetched_at: str,
) -> list[StepSnapshot]:
    """Transform daily steps into a StepSnapshot."""
    entries = payload.get("activities-steps", [])
    if not entries:
        return []

    steps = int(entries[0].get("value", 0))
    return [
        StepSnapshot(
            source="fitbit",
            fetched_at=fetched_at,
            date=date,
            observed_at=fetched_at,
            steps=steps,
        )
    ]


def transform_calories(
    payload: dict,
    date: str,
    fetched_at: str,
) -> list[CalorieSnapshot]:
    """Transform daily calories into a CalorieSnapshot."""
    entries = payload.get("activities-calories", [])
    if not entries:
        return []

    calories = int(entries[0].get("value", 0))
    return [
        CalorieSnapshot(
            source="fitbit",
            fetched_at=fetched_at,
            date=date,
            observed_at=fetched_at,
            calories=calories,
        )
    ]


def transform_activities(
    payload: dict,
    date: str,
    fetched_at: str,
) -> tuple[
    list[ActiveMinutesSnapshot],
    list[ActivityLevelSnapshot],
    list[DistanceSnapshot],
    list[ActivitySession],
    list[GoalSnapshot],
]:
    """Transform activity summary into canonical records.

    Returns five lists: active-minutes snapshots,
    activity-level snapshots, distance snapshots,
    activity sessions, and goal snapshots.
    """
    summary = payload.get("summary", {})

    fairly = summary.get("fairlyActiveMinutes", 0)
    very = summary.get("veryActiveMinutes", 0)

    active_minutes = [
        ActiveMinutesSnapshot(
            source="fitbit",
            fetched_at=fetched_at,
            date=date,
            observed_at=fetched_at,
            fairly_active=fairly,
            very_active=very,
        )
    ]

    activity_levels = [
        ActivityLevelSnapshot(
            source="fitbit",
            fetched_at=fetched_at,
            date=date,
            observed_at=fetched_at,
            sedentary_minutes=summary.get(
                "sedentaryMinutes", 0
            ),
            lightly_active_minutes=summary.get(
                "lightlyActiveMinutes", 0
            ),
            fairly_active_minutes=fairly,
            very_active_minutes=very,
        )
    ]

    distances_raw = summary.get("distances", [])
    total_distance = sum(
        d.get("distance", 0)
        for d in distances_raw
        if d.get("activity") == "total"
    )
    distance = [
        DistanceSnapshot(
            source="fitbit",
            fetched_at=fetched_at,
            date=date,
            observed_at=fetched_at,
            distance_km=round(total_distance, 2),
            floors=summary.get("floors", 0),
            elevation=summary.get("elevation", 0.0),
        )
    ]

    sessions = [
        ActivitySession(
            source="fitbit",
            fetched_at=fetched_at,
            date=date,
            start_time=act.get("startTime", ""),
            name=act.get("name", "Unknown"),
            calories=act.get("calories", 0),
            duration_min=round(
                act.get("duration", 0) / 60000, 1
            ),
            steps=act.get("steps", 0),
        )
        for act in payload.get("activities", [])
    ]

    goals_raw = payload.get("goals", {})
    goals: list[GoalSnapshot] = []
    if goals_raw:
        goals = [
            GoalSnapshot(
                source="fitbit",
                fetched_at=fetched_at,
                date=date,
                observed_at=fetched_at,
                steps_goal=goals_raw.get("steps", 0),
                active_minutes_goal=goals_raw.get(
                    "activeMinutes", 0
                ),
            )
        ]

    return (
        active_minutes, activity_levels, distance,
        sessions, goals,
    )


def transform_sleep(
    payload: dict,
    date: str,
    fetched_at: str,
) -> tuple[list[SleepSession], list[SleepStage]]:
    """Transform sleep data into SleepSessions and SleepStages.

    Returns all sleep sessions for the date (not just main).
    """
    sessions = []
    stages = []

    for sleep in payload.get("sleep", []):
        bedtime = sleep.get("startTime", "")
        wake_time = sleep.get("endTime", "")
        duration_ms = sleep.get("duration", 0)
        duration_hours = round(duration_ms / 3600000, 1)

        session = SleepSession(
            source="fitbit",
            fetched_at=fetched_at,
            date=date,
            bedtime=bedtime,
            wake_time=wake_time,
            duration_hours=duration_hours,
            score=sleep.get("efficiency", 0),
            is_main=sleep.get("isMainSleep", False),
        )
        sessions.append(session)

        level_summary = (
            sleep.get("levels", {}).get("summary", {})
        )
        for stage_name, stage_data in level_summary.items():
            if stage_name == "wake":
                stage_name = "awake"
            stages.append(
                SleepStage(
                    source="fitbit",
                    fetched_at=fetched_at,
                    date=date,
                    bedtime=bedtime,
                    stage=stage_name,
                    minutes=stage_data.get("minutes", 0),
                )
            )

    return sessions, stages


def transform_body(
    payload: dict,
    date: str,
    fetched_at: str,
) -> list[BodyMeasurement]:
    """Transform body data into a BodyMeasurement."""
    body = payload.get("body", {})
    weight = body.get("weight", 0.0)
    fat = body.get("fat", 0.0)
    bmi = body.get("bmi", 0.0)

    if not weight and not fat and not bmi:
        return []

    return [
        BodyMeasurement(
            source="fitbit",
            fetched_at=fetched_at,
            date=date,
            weight_kg=weight,
            body_fat_pct=fat,
            bmi=bmi,
            muscle_mass_kg=0.0,
            chest_cm=0.0,
            waist_cm=0.0,
            hips_cm=0.0,
            bicep_cm=0.0,
            thigh_cm=0.0,
        )
    ]
