"""Sensor row generators. Pure functions: (pose, rng, ts) -> row dict.

Every row carries int64 epoch nanoseconds. Values are emitted at full float
precision - quantization happens only in the broadcast payload, never in
stored telemetry.
"""

from __future__ import annotations

import math
import random
from typing import Any

from .flight import Pose

Row = dict[str, Any]


def imu_row(pose: Pose, rng: random.Random, ts_ns: int) -> Row:
    return {
        "ts_ns": ts_ns,
        "accel_x": rng.gauss(0.0, 0.35),
        "accel_y": rng.gauss(0.0, 0.35),
        "accel_z": rng.gauss(-9.81, 0.25),
        "gyro_x": math.radians(rng.gauss(pose.roll, 0.8)),
        "gyro_y": math.radians(rng.gauss(pose.pitch, 0.8)),
        "gyro_z": math.radians(rng.gauss(0.0, 0.5)),
    }


def baro_row(pose: Pose, rng: random.Random, ts_ns: int) -> Row:
    pressure = 101325.0 * math.exp(-pose.z / 8434.0) + rng.gauss(0.0, 4.0)
    return {"ts_ns": ts_ns, "pressure_pa": pressure, "alt_est_m": pose.z + rng.gauss(0.0, 0.3)}


def temp_row(_pose: Pose, rng: random.Random, ts_ns: int) -> Row:
    return {
        "ts_ns": ts_ns,
        "cpu_c": 55.0 + rng.gauss(0.0, 3.0),
        "gpu_c": 62.0 + rng.gauss(0.0, 4.0),
        "ambient_c": 24.0 + rng.gauss(0.0, 0.5),
    }


def battery_row(_pose: Pose, rng: random.Random, ts_ns: int, elapsed_s: float, duration_s: float) -> Row:
    level = max(0.0, 100.0 - 80.0 * elapsed_s / max(duration_s, 1.0) + rng.gauss(0.0, 0.2))
    return {"ts_ns": ts_ns, "level_pct": level, "voltage_v": 22.2 * (0.85 + 0.15 * level / 100.0)}


DETECTION_CLASSES = ("vehicle", "person", "animal", "structure", "unknown")


def detection_row(pose: Pose, rng: random.Random, ts_ns: int) -> Row:
    return {
        "ts_ns": ts_ns,
        "cls": rng.choice(DETECTION_CLASSES),
        "confidence": round(rng.uniform(0.42, 0.99), 3),
        "obj_x": pose.x + rng.uniform(-40.0, 40.0),
        "obj_y": pose.y + rng.uniform(-40.0, 40.0),
        "obj_z": rng.uniform(0.0, 5.0),
        "ego_x": pose.x,
        "ego_y": pose.y,
        "ego_z": pose.z,
    }


def state_row(pose: Pose, ts_ns: int) -> Row:
    return {
        "ts_ns": ts_ns,
        "pos_x": pose.x,
        "pos_y": pose.y,
        "pos_z": pose.z,
        "roll": pose.roll,
        "pitch": pose.pitch,
        "yaw": pose.yaw,
        "vel_x": pose.vx,
        "vel_y": pose.vy,
        "vel_z": pose.vz,
        "frame_ref": 0,
    }
