"""Plane/coastal radar track generator (synthetic surface tracks).

Emits radar fixes at 1–4 Hz for a given track. Drone radar uses the same
structure but with altitude on the third axis.
"""
from __future__ import annotations

import random
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from typing import Any

from .common import iso_utc, epoch_ms, interp_waypoints, time_range


@dataclass
class RadarTrack:
    track_id: str
    sensor_id: str
    waypoints: list[tuple[datetime, float, float]]
    cadence_s: float = 4.0
    classification: str = "surface_large"
    rcs_m2: float = 800.0
    alt_m: float | None = None  # used for air tracks
    confidence: float = 0.85
    seed: int | None = None


def emit_radar(track: RadarTrack) -> list[dict[str, Any]]:
    rng = random.Random(track.seed)
    start = track.waypoints[0][0]
    end = track.waypoints[-1][0]
    out: list[dict[str, Any]] = []
    for t in time_range(start, end, track.cadence_s):
        lat, lon, sog_kn, cog = interp_waypoints(track.waypoints, t)
        # Add radar noise
        lat += rng.gauss(0.0, 0.0001)
        lon += rng.gauss(0.0, 0.0001)
        rec: dict[str, Any] = {
            "timestamp": iso_utc(t),
            "ts_epoch_ms": epoch_ms(t),
            "track_id": track.track_id,
            "sensor_id": track.sensor_id,
            "lat": round(lat, 6),
            "lon": round(lon, 6),
            "sog_kn": round(sog_kn, 2),
            "cog_deg": round(cog, 1),
            "rcs_m2": round(track.rcs_m2 * (1.0 + rng.gauss(0.0, 0.08)), 2),
            "classification": track.classification,
            "confidence": round(min(1.0, max(0.0, track.confidence + rng.gauss(0.0, 0.03))), 3),
        }
        if track.alt_m is not None:
            rec["alt_m"] = round(track.alt_m + rng.gauss(0.0, 5.0), 1)
        out.append(rec)
    return out


def surface_to_air_record(rec: dict[str, Any], *, alt_m: float = 0.0) -> dict[str, Any]:
    """Convert an `emit_radar` (surface) record into the drone-radar shape:
    drop `sog_kn`/`cog_deg`, add `speed_mps`/`heading_deg`/`alt_m`.

    Used when surface tracks (e.g. patrol drone seeing the suspect ship as a
    surface contact) are emitted into a drone-radar stream whose KQL DDL
    declares `alt_m, speed_mps, heading_deg` instead of `sog_kn, cog_deg`.
    """
    sog = rec.pop("sog_kn", None)
    cog = rec.pop("cog_deg", None)
    if "speed_mps" not in rec:
        rec["speed_mps"] = round((sog or 0.0) * 0.514444, 2)
    if "heading_deg" not in rec:
        rec["heading_deg"] = round(cog or 0.0, 1)
    if "alt_m" not in rec:
        rec["alt_m"] = float(alt_m)
    return rec


def emit_drone_radar(track: RadarTrack, altitudes: list[tuple[datetime, float]] | None = None) -> list[dict[str, Any]]:
    """Drone radar with per-time altitude profile."""
    rng = random.Random(track.seed)
    start = track.waypoints[0][0]
    end = track.waypoints[-1][0]
    out: list[dict[str, Any]] = []

    def alt_at(t: datetime) -> float:
        if not altitudes:
            return float(track.alt_m or 0.0)
        if t <= altitudes[0][0]:
            return altitudes[0][1]
        if t >= altitudes[-1][0]:
            return altitudes[-1][1]
        for i in range(len(altitudes) - 1):
            a, b = altitudes[i], altitudes[i + 1]
            if a[0] <= t <= b[0]:
                span = (b[0] - a[0]).total_seconds()
                f = 0.0 if span <= 0 else (t - a[0]).total_seconds() / span
                return a[1] + f * (b[1] - a[1])
        return altitudes[-1][1]

    for t in time_range(start, end, track.cadence_s):
        lat, lon, sog_kn, cog = interp_waypoints(track.waypoints, t)
        out.append({
            "timestamp": iso_utc(t),
            "ts_epoch_ms": epoch_ms(t),
            "track_id": track.track_id,
            "sensor_id": track.sensor_id,
            "lat": round(lat + rng.gauss(0.0, 0.00005), 6),
            "lon": round(lon + rng.gauss(0.0, 0.00005), 6),
            "alt_m": round(alt_at(t) + rng.gauss(0.0, 2.0), 1),
            "speed_mps": round(sog_kn * 0.514444 + rng.gauss(0, 0.5), 2),
            "heading_deg": round(cog, 1),
            "rcs_m2": round(track.rcs_m2 * (1.0 + rng.gauss(0.0, 0.15)), 3),
            "classification": track.classification,
            "confidence": round(min(1.0, max(0.0, track.confidence + rng.gauss(0.0, 0.05))), 3),
        })
    return out
