"""Telemetry comparisons and objective pilot gate metrics."""
from __future__ import annotations

from typing import Any

import numpy as np


def rms(values: np.ndarray, axis: int | tuple[int, ...] | None = None) -> np.ndarray:
    return np.sqrt(np.mean(np.asarray(values, dtype=float) ** 2, axis=axis))


def dominant_frequency(values: np.ndarray, sample_spacing: float = 1.0) -> float:
    signal = np.asarray(values, dtype=float).reshape(-1)
    if len(signal) < 4:
        return 0.0
    centered = signal - signal.mean()
    spectrum = np.abs(np.fft.rfft(centered)) ** 2
    frequencies = np.fft.rfftfreq(len(centered), d=sample_spacing)
    if len(spectrum) <= 1 or np.allclose(spectrum[1:], 0):
        return 0.0
    return float(frequencies[1 + np.argmax(spectrum[1:])])


def normalized_dtw_similarity(reference: np.ndarray, candidate: np.ndarray) -> float:
    a, b = np.asarray(reference, dtype=float).reshape(-1), np.asarray(candidate, dtype=float).reshape(-1)
    if len(a) == 0 or len(b) == 0:
        raise ValueError("DTW requires non-empty signals")
    scale = max(float(np.std(a)), float(np.std(b)), 1e-12)
    previous = np.full(len(b) + 1, np.inf)
    previous[0] = 0.0
    for x in a:
        current = np.full(len(b) + 1, np.inf)
        for j, y in enumerate(b, start=1):
            current[j] = abs(x - y) / scale + min(current[j - 1], previous[j], previous[j - 1])
        previous = current
    distance = previous[-1] / (len(a) + len(b))
    return float(np.exp(-distance))


def compare_telemetry(reference: dict[str, np.ndarray], candidate: dict[str, np.ndarray]) -> dict[str, Any]:
    result: dict[str, Any] = {}
    for key in ("sensors", "forces", "actions"):
        if key not in reference or key not in candidate:
            continue
        a, b = np.asarray(reference[key]), np.asarray(candidate[key])
        if a.shape != b.shape:
            raise ValueError(f"{key} shapes differ: {a.shape} vs {b.shape}")
        natural = np.std(a, axis=0)
        error_rms = rms(b - a, axis=0)
        result[key] = {
            "max_abs_error": float(np.max(np.abs(b - a))),
            "error_rms_by_channel": error_rms.tolist(),
            "natural_std_by_channel": natural.tolist(),
            "relative_rms_to_natural": (error_rms / np.maximum(natural, 1e-12)).tolist(),
        }
    sensor_a = np.asarray(reference["sensors"])
    sensor_b = np.asarray(candidate["sensors"])
    similarities = [normalized_dtw_similarity(sensor_a[:, i], sensor_b[:, i]) for i in range(sensor_a.shape[1])]
    frequencies_a = [dominant_frequency(sensor_a[:, i]) for i in range(sensor_a.shape[1])]
    frequencies_b = [dominant_frequency(sensor_b[:, i]) for i in range(sensor_b.shape[1])]
    frequency_rel = [abs(x - y) / max(abs(x), 1e-12) for x, y in zip(frequencies_a, frequencies_b)]
    result["sensor_dtw_similarity_by_channel"] = similarities
    result["sensor_dtw_degradation"] = float(1.0 - np.mean(similarities))
    result["dominant_frequency_reference"] = frequencies_a
    result["dominant_frequency_candidate"] = frequencies_b
    result["dominant_frequency_max_relative_difference"] = float(max(frequency_rel))
    return result
