"""绘制横向误差和航向误差随时间变化图。"""

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 (
    build_reference,
    configure_matplotlib,
    discover_csv_files,
    load_and_resample,
    output_path,
    shade_localization_jump_windows,
)


def plot_errors(
    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,
    )
    reference = build_reference(frame, metadata)
    time = frame["TimeSeconds"].to_numpy()
    lateral = np.asarray(reference["lateral_error_mm"])
    heading = np.asarray(reference["heading_error_degrees"])
    invalid = frame[
        "InvalidNearLocalizationJump"
    ].to_numpy(dtype=bool)
    lateral_for_statistics = lateral.copy()
    heading_for_statistics = heading.copy()
    lateral_for_statistics[invalid] = np.nan
    heading_for_statistics[invalid] = np.nan

    lateral_rmse = float(
        np.sqrt(np.nanmean(lateral_for_statistics**2))
    )
    heading_rmse = float(
        np.sqrt(np.nanmean(heading_for_statistics**2))
    )
    lateral_max = float(
        np.nanmax(np.abs(lateral_for_statistics))
    )
    heading_max = float(
        np.nanmax(np.abs(heading_for_statistics))
    )
    is_in_place_rotation = (
        reference["kind"] == "in_place_rotation"
    )

    fig, axes = plt.subplots(
        2,
        1,
        figsize=(10.0, 7.0),
        sharex=True,
    )
    axes[0].plot(time, lateral, linewidth=1.5)
    axes[0].axhline(0.0, color="black", linewidth=0.8)
    if is_in_place_rotation:
        axes[0].set_ylabel("旋转中心位置漂移 / mm")
        axes[0].set_title(
            f"原地自转位置漂移：RMS={lateral_rmse:.2f} mm，"
            f"最大值={lateral_max:.2f} mm"
        )
    else:
        axes[0].set_ylabel("横向误差 / mm")
        axes[0].set_title(
            f"横向误差：RMSE={lateral_rmse:.2f} mm，"
            f"最大绝对值={lateral_max:.2f} mm"
        )
    shade_localization_jump_windows(axes[0], metadata)
    axes[0].grid(True, alpha=0.3)

    axes[1].plot(
        time,
        heading,
        color="tab:orange",
        linewidth=1.5,
    )
    axes[1].axhline(0.0, color="black", linewidth=0.8)
    axes[1].set_xlabel("时间 / s")
    axes[1].set_ylabel(
        "目标角度剩余误差 / °"
        if is_in_place_rotation
        else "航向误差 / °"
    )
    axes[1].set_title(
        (
            f"目标角度剩余误差：RMSE={heading_rmse:.2f}°，"
            f"最大绝对值={heading_max:.2f}°"
        )
        if is_in_place_rotation
        else (
            f"航向误差：RMSE={heading_rmse:.2f}°，"
            f"最大绝对值={heading_max:.2f}°"
        )
    )
    shade_localization_jump_windows(axes[1], metadata)
    axes[1].grid(True, alpha=0.3)
    if metadata["localization_jump_events"]:
        axes[1].legend(loc="best")

    fig.suptitle(
        f"横向/航向误差随时间变化\n"
        f"{metadata['controller_name']} - "
        f"{metadata['trajectory_name']}"
    )
    fig.tight_layout()

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

    if is_in_place_rotation:
        print(
            f"{csv_path.name}: position drift RMS="
            f"{lateral_rmse:.3f} mm, "
            f"target-angle error RMS={heading_rmse:.3f} deg"
        )
    else:
        print(
            f"{csv_path.name}: lateral RMSE="
            f"{lateral_rmse:.3f} mm, "
            f"heading RMSE={heading_rmse:.3f} deg"
        )
    return destination


def main() -> None:
    configure_matplotlib()
    parser = argparse.ArgumentParser(
        description="绘制横向误差和航向误差随时间变化图。"
    )
    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_errors(
            csv_path,
            args.frequency,
            args.window,
            args.output_dir,
            args.show,
        )
        print(f"已生成：{destination}")


if __name__ == "__main__":
    main()
