"""Pretty-print calibration summary.json and optionally write a small preview figure."""

from __future__ import annotations

import argparse
import json
from pathlib import Path


def _load(path: Path) -> dict:
    return json.loads(path.read_text(encoding="utf-8"))


def _session0(summary: dict) -> dict:
    sessions = summary.get("details", {}).get("sessions", [])
    return sessions[0] if sessions else {}


def print_report(summary: dict, truth: dict | None = None) -> None:
    print("---------- calibration report ----------")
    print(f"status : {summary.get('status')}")
    print(f"message: {summary.get('message')}")
    dt = summary.get("time_offset_s")
    if dt is not None:
        print(f"δt     : {dt:.6f} s   (t_imu = t_lidar + δt)")
        if truth and "delta_t_s" in truth:
            print(f"         truth={truth['delta_t_s']:.6f} s  err={dt - truth['delta_t_s']:+.6f} s")

    t_block = summary.get("T_IMU_lidar")
    if isinstance(t_block, dict):
        rpy = t_block.get("rpy_deg_xyz")
        trans = t_block.get("translation_m")
        if rpy is not None:
            print(f"RPY xyz: [{rpy[0]:.3f}, {rpy[1]:.3f}, {rpy[2]:.3f}] deg")
            if truth and "yaw_extrinsic_deg" in truth:
                print(f"         yaw truth≈{truth['yaw_extrinsic_deg']:.3f} deg")
        if trans is not None:
            print(f"t      : [{trans[0]:.4f}, {trans[1]:.4f}, {trans[2]:.4f}] m")

    session = _session0(summary)
    handeye = session.get("handeye") or {}
    joint = session.get("joint") or {}
    if handeye:
        print(
            "handeye: "
            f"pairs={handeye.get('pair_count')}  "
            f"rms={handeye.get('residual_rms_deg')}°  "
            f"median={handeye.get('residual_median_deg')}°  "
            f"ok={handeye.get('ok')}"
        )
    if joint:
        obs = joint.get("observability") or {}
        print(
            "joint  : "
            f"rot_rms={joint.get('residual_rms_rot_deg')}°  "
            f"trans_rms={joint.get('residual_rms_trans_m')} m  "
            f"trans_accepted={joint.get('translation_accepted')}"
        )
        print(
            "observ : "
            f"rotation={obs.get('rotation_observable')}  "
            f"translation={obs.get('translation_observable')}  "
            f"cond_R={obs.get('condition_rotation')}"
        )
        if joint.get("gravity_m_s2") is not None:
            print(f"gravity: {joint.get('gravity_m_s2')}")
        if joint.get("gyro_bias_rad_s") is not None:
            print(f"b_g    : {joint.get('gyro_bias_rad_s')}")
    print("----------------------------------------")


def maybe_plot(summary: dict, plot_path: Path, truth: dict | None = None) -> None:
    try:
        import matplotlib.pyplot as plt
    except ImportError:
        print("(matplotlib not installed; skip plot)")
        return

    session = _session0(summary)
    handeye = session.get("handeye") or {}
    joint = session.get("joint") or {}
    labels = []
    values = []
    if handeye.get("residual_rms_deg") is not None:
        labels.append("handeye\nRMS (°)")
        values.append(float(handeye["residual_rms_deg"]))
    if joint.get("residual_rms_rot_deg") is not None:
        labels.append("joint rot\nRMS (°)")
        values.append(float(joint["residual_rms_rot_deg"]))
    if joint.get("residual_rms_trans_m") is not None:
        labels.append("joint trans\nRMS (m)")
        values.append(float(joint["residual_rms_trans_m"]))
    dt = summary.get("time_offset_s")
    if dt is not None:
        labels.append("|δt| (s)")
        values.append(abs(float(dt)))
        if truth and "delta_t_s" in truth:
            labels.append("|δt err| (s)")
            values.append(abs(float(dt) - float(truth["delta_t_s"])))

    if not labels:
        print("(no numeric fields to plot)")
        return

    fig, ax = plt.subplots(figsize=(7.5, 3.8))
    ax.bar(labels, values, color="#3b6ea5")
    ax.set_title(f"Calibration preview — {summary.get('status')}")
    ax.set_ylabel("value")
    ax.grid(axis="y", alpha=0.3)
    fig.tight_layout()
    plot_path.parent.mkdir(parents=True, exist_ok=True)
    fig.savefig(plot_path, dpi=120)
    plt.close(fig)
    print(f"wrote plot: {plot_path}")


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(description="Show LiDAR–IMU calibration summary")
    parser.add_argument("--summary", type=Path, required=True, help="Path to summary.json")
    parser.add_argument("--truth-meta", type=Path, default=None, help="Optional synthetic meta.json")
    parser.add_argument("--plot", type=Path, default=None, help="Optional PNG path for a bar chart")
    args = parser.parse_args(argv)

    summary = _load(args.summary)
    truth = _load(args.truth_meta) if args.truth_meta and args.truth_meta.exists() else None
    print_report(summary, truth)
    if args.plot is not None:
        maybe_plot(summary, args.plot, truth)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
