"""Kinematics: a seeded patrol route and the drone's motion along it."""

from __future__ import annotations

import math
import random
from dataclasses import dataclass, replace

from .config import Config


@dataclass(frozen=True)
class Pose:
    ts_ns: int
    x: float
    y: float
    z: float
    roll: float
    pitch: float
    yaw: float
    vx: float
    vy: float
    vz: float


def make_waypoints(cfg: Config, rng: random.Random) -> list[tuple[float, float]]:
    """Perimeter patrol with per-drone jitter so drones do not overlap."""
    s = cfg.area_size_m
    jitter = rng.uniform(0.05, 0.20) * s
    corners = [(jitter, jitter), (s - jitter, jitter), (s - jitter, s - jitter), (jitter, s - jitter)]
    start = rng.randrange(4)
    return corners[start:] + corners[:start]


def initial_pose(cfg: Config, rng: random.Random, ts_ns: int) -> Pose:
    wps = make_waypoints(cfg, rng)
    x, y = wps[0]
    return Pose(ts_ns=ts_ns, x=x, y=y, z=cfg.cruise_alt_m, roll=0.0, pitch=0.0, yaw=0.0, vx=0.0, vy=0.0, vz=0.0)


def step(pose: Pose, target: tuple[float, float], cfg: Config, rng: random.Random, dt: float, ts_ns: int) -> tuple[Pose, bool]:
    """Advance one tick toward the target waypoint. Returns (pose, reached)."""
    dx, dy = target[0] - pose.x, target[1] - pose.y
    dist = math.hypot(dx, dy)
    reached = dist < cfg.cruise_speed_ms * dt * 2

    speed = cfg.cruise_speed_ms * rng.uniform(0.9, 1.1)
    if dist > 1e-6:
        vx, vy = dx / dist * speed, dy / dist * speed
    else:
        vx, vy = 0.0, 0.0

    yaw = math.degrees(math.atan2(vy, vx))
    # Small attitude noise around the commanded values
    roll = rng.gauss(0.0, 1.5)
    pitch = rng.gauss(2.0, 1.0)
    z = cfg.cruise_alt_m + rng.gauss(0.0, 0.5)
    vz = (z - pose.z) / dt if dt > 0 else 0.0

    return (
        replace(
            pose,
            ts_ns=ts_ns,
            x=pose.x + vx * dt,
            y=pose.y + vy * dt,
            z=z,
            roll=roll,
            pitch=pitch,
            yaw=yaw,
            vx=vx,
            vy=vy,
            vz=vz,
        ),
        reached,
    )
