"""绘制控制器参考速度与Detour差分实际速度对比图。"""

from __future__ import annotations

import argparse
from pathlib import Path

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np

from plot_trajectory_comparison import (
    configure_matplotlib,
    discover_csv_files,
    load_and_resample,
    output_path,
    segmented_savgol,
    shade_localization_jump_windows,
)


def calculate_actual_speed_mps(
    frame,
    filter_window_seconds: float,
) -> np.ndarray:
    """使用Savitzky-Golay求位置导数并计算Detour实际合速度。"""
    time = frame["TimeSeconds"].to_numpy(dtype=float)
    dt = float(np.median(np.diff(time)))
    # 直接对固定频率重采样后的位置做SG求导，避免“先平滑再求导”
    # 造成两次滤波和过度削弱速度峰值。
    x_mm = frame["DetourXRawMm"].to_numpy(dtype=float)
    y_mm = frame["DetourYRawMm"].to_numpy(dtype=float)
    vx_mm_per_second = segmented_savgol(
        x_mm,
        dt,
        filter_window_seconds,
        derivative=1,
    )
    vy_mm_per_second = segmented_savgol(
        y_mm,
        dt,
        filter_window_seconds,
        derivative=1,
    )

    speed = np.hypot(
        vx_mm_per_second,
        vy_mm_per_second,
    ) / 1000.0
    speed[
        frame["InvalidNearLocalizationJump"].to_numpy(dtype=bool)
    ] = np.nan
    return speed


def plot_speed(
    csv_path: Path,
    frequency_hz: float,
    filter_window_seconds: float,
    output_directory: str | None,
    show: bool,
) -> Path:
    """生成单份CSV的参考/实际速度响应图。"""
    frame, metadata = load_and_resample(
        csv_path,
        frequency_hz,
        filter_window_seconds,
    )
    time = frame["TimeSeconds"].to_numpy(dtype=float)
    command_speed = frame["CommandSpeedMps"].to_numpy(dtype=float)
    actual_speed = calculate_actual_speed_mps(
        frame,
        filter_window_seconds,
    )
    is_in_place_rotation = (
        str(metadata["trajectory_name"])
        .lower()
        .startswith("rotate")
    )
    # 原地自转CSV中的ReferenceSpeed历史上保存的是角速度上限deg/s，
    # 不能作为线速度m/s使用；其参考线速度应为0。
    configured_speed = (
        0.0
        if is_in_place_rotation
        else float(metadata["reference_speed_mps"])
    )

    moving = (
        (command_speed > max(0.02, configured_speed * 0.1)) &
        np.isfinite(actual_speed)
    )
    if np.any(moving):
        speed_rmse = float(
            np.sqrt(
                np.mean(
                    (actual_speed[moving] - command_speed[moving]) ** 2
                )
            )
        )
    else:
        speed_rmse = float("nan")

    fig, ax = plt.subplots(figsize=(10.0, 5.8))
    ax.plot(
        time,
        command_speed,
        linewidth=1.8,
        label="控制器参考/下发线速度",
    )
    ax.plot(
        time,
        actual_speed,
        linewidth=1.5,
        label="Detour差分实际线速度（SG求导）",
    )
    ax.axhline(
        configured_speed,
        linestyle=":",
        linewidth=1.3,
        color="tab:green",
        label=(
            "原地自转参考线速度 0 m/s"
            if is_in_place_rotation
            else f"配置巡航速度 {configured_speed:.3f} m/s"
        ),
    )
    shade_localization_jump_windows(ax, metadata)
    ax.set_xlabel("时间 / s")
    ax.set_ylabel("线速度 / (m/s)")
    ax.set_title(
        f"参考速度与实际速度对比\n"
        f"{metadata['controller_name']} - "
        f"{metadata['trajectory_name']}，"
        f"运动段RMSE={speed_rmse:.4f} m/s"
    )
    ax.grid(True, alpha=0.3)
    ax.legend()
    fig.tight_layout()

    destination = output_path(
        csv_path,
        output_directory,
        "speed_response",
    )
    fig.savefig(destination, dpi=300, bbox_inches="tight")
    if show:
        plt.show()
    plt.close(fig)
    return destination


def main() -> None:
    configure_matplotlib()
    parser = argparse.ArgumentParser(
        description="绘制参考速度与Detour差分实际速度对比图。"
    )
    parser.add_argument("files", nargs="*", help="一个或多个CSV文件")
    parser.add_argument("--frequency", type=float, default=20.0)
    parser.add_argument("--window", type=float, default=0.55)
    parser.add_argument("--output-dir")
    parser.add_argument("--show", action="store_true")
    args = parser.parse_args()

    for csv_path in discover_csv_files(args.files):
        destination = plot_speed(
            csv_path,
            args.frequency,
            args.window,
            args.output_dir,
            args.show,
        )
        print(f"已生成：{destination}")


if __name__ == "__main__":
    main()
