#!/usr/bin/env python3
"""底盘标定现场数据离线回放和数据输入自检入口。"""

from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

from chassis_data_common import (
    ACTUATOR_COMMAND_FIELDS,
    CHASSIS_MOTION_FIELDS,
    TRUTH_TRAJECTORY_FIELDS,
    apply_cli_overrides,
    build_dataset_index,
    build_summary,
    copy_or_generate_file,
    load_config,
    read_csv_rows,
    resolve_path,
    synthetic_rows,
    validate_chassis_dataset_files,
    validate_config,
    validate_summary,
    write_yaml,
)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="验证底盘标定现场数据文件、dataset_index 写入和 data_input 转换链路。"
    )
    parser.add_argument("--config", required=True, help="底盘标定现场数据配置文件。")
    parser.add_argument("--chassis-type", default="", help="覆盖 chassis_type。")
    parser.add_argument("--session-id", default="", help="覆盖 session_id。")
    parser.add_argument("--site-id", default="", help="覆盖 site_id。")
    parser.add_argument("--vehicle-id", default="", help="覆盖 vehicle_id。")
    parser.add_argument("--session-dir", default="", help="覆盖 session_dir。")
    parser.add_argument("--dataset-index-path", default="", help="覆盖 dataset_index_path。")
    parser.add_argument("--chassis-motion-csv", default="", help="真实底盘遥测 CSV。")
    parser.add_argument("--actuator-command-csv", default="", help="真实执行器命令 CSV。")
    parser.add_argument("--truth-trajectory-csv", default="", help="真实外部真值轨迹 CSV。")
    parser.add_argument(
        "--no-synthetic",
        action="store_true",
        help="缺少任一输入 CSV 时直接报错，不生成合成数据。",
    )
    return parser.parse_args()


def require_inputs(args: argparse.Namespace) -> None:
    if args.no_synthetic and (
        not args.chassis_motion_csv or not args.actuator_command_csv or not args.truth_trajectory_csv
    ):
        raise ValueError("--no-synthetic 要求同时提供三类 CSV 输入。")


def main() -> int:
    args = parse_args()
    require_inputs(args)
    config_path = Path(args.config).expanduser().resolve(strict=False)
    config = load_config(config_path)
    apply_cli_overrides(config, args)

    validation = validate_config(config, config_path)
    for warning in validation.warnings:
        print(f"[WARN] {warning}", file=sys.stderr)
    if not validation.ok:
        for error in validation.errors:
            print(f"[错误] {error}", file=sys.stderr)
        return 1

    session_dir = Path(str(config["session_dir"])).expanduser().resolve(strict=False)
    files = config["files"]
    target_paths = {
        "chassis_motion_data_file": resolve_path(session_dir, str(files["chassis_motion_data_file"])),
        "actuator_command_file": resolve_path(session_dir, str(files["actuator_command_file"])),
        "truth_trajectory_file": resolve_path(session_dir, str(files["truth_trajectory_file"])),
        "diagnostics_file": resolve_path(session_dir, str(files["diagnostics_file"])),
    }

    chassis_rows, command_rows, truth_rows = synthetic_rows(config)
    copy_or_generate_file(
        args.chassis_motion_csv,
        target_paths["chassis_motion_data_file"],
        CHASSIS_MOTION_FIELDS,
        chassis_rows,
    )
    copy_or_generate_file(
        args.actuator_command_csv,
        target_paths["actuator_command_file"],
        ACTUATOR_COMMAND_FIELDS,
        command_rows,
    )
    copy_or_generate_file(
        args.truth_trajectory_csv,
        target_paths["truth_trajectory_file"],
        TRUTH_TRAJECTORY_FIELDS,
        truth_rows,
    )

    contract_validation = validate_chassis_dataset_files(target_paths)
    for warning in contract_validation.warnings:
        print(f"[WARN] {warning}", file=sys.stderr)
    if not contract_validation.ok:
        for error in contract_validation.errors:
            print(f"[错误] {error}", file=sys.stderr)
        return 1

    actual_chassis_rows = read_csv_rows(target_paths["chassis_motion_data_file"])
    actual_command_rows = read_csv_rows(target_paths["actuator_command_file"])
    actual_truth_rows = read_csv_rows(target_paths["truth_trajectory_file"])
    summary = build_summary(actual_chassis_rows, actual_command_rows, actual_truth_rows, config)

    summary_validation = validate_summary(summary, config)
    for warning in summary_validation.warnings:
        print(f"[WARN] {warning}", file=sys.stderr)
    if not summary_validation.ok:
        for error in summary_validation.errors:
            print(f"[错误] {error}", file=sys.stderr)
        return 1

    target_paths["diagnostics_file"].parent.mkdir(parents=True, exist_ok=True)
    target_paths["diagnostics_file"].write_text(
        json.dumps(summary, ensure_ascii=False, indent=2) + "\n",
        encoding="utf-8",
    )

    dataset_index = build_dataset_index(config, summary, target_paths, config_path)
    dataset_index_path = Path(str(config["dataset_index_path"])).expanduser().resolve(strict=False)
    write_yaml(dataset_index_path, dataset_index)
    print(json.dumps(summary, ensure_ascii=False, separators=(",", ":")))
    print(f"[OK] 已写入底盘数据集索引: {dataset_index_path}", file=sys.stderr)
    return 0


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except Exception as exc:
        print(f"[错误] {exc}", file=sys.stderr)
        raise SystemExit(1)
