#!/usr/bin/env python3
"""收尾真实标定会话，并生成算法服务数据输入参数文件。"""

from __future__ import annotations

import argparse
import sys
from pathlib import Path
from typing import Any

import yaml

from dataset_index_to_site_data_input import (
    build_ros_params,
    load_yaml,
    validate_output,
)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="根据现场 profile 和本次会话数据集索引生成 site_data_input.yaml。"
    )
    parser.add_argument(
        "--site-profile",
        default="src/deployment/profiles/site_template.yaml",
        help="现场部署 profile 路径。",
    )
    parser.add_argument(
        "--session-id",
        help="本次标定会话 ID；未提供 --session-dir 时，会拼到 dataset_root 后面。",
    )
    parser.add_argument(
        "--session-dir",
        help="本次标定会话目录；优先级高于 --session-id。",
    )
    parser.add_argument(
        "--dataset-index",
        help="本次会话 dataset_index.yaml 路径；优先级高于 profile 中的约定。",
    )
    parser.add_argument(
        "-o",
        "--output",
        help="输出的 site_data_input.yaml 路径；默认写入会话目录。",
    )
    parser.add_argument(
        "--no-strict",
        action="store_true",
        help="关闭严格检查；默认要求时间窗口有效并且存在数据文件引用。",
    )
    parser.add_argument(
        "--no-index-reference",
        action="store_true",
        help="不自动把 dataset_index.yaml 写入 sensor 的 synchronized_dataset_files。",
    )
    return parser.parse_args()


def require_map(value: Any, field_name: str) -> dict[str, Any]:
    if not isinstance(value, dict):
        raise ValueError(f"{field_name} 必须是 YAML map。")
    return value


def resolve_relative(path_value: str, base_dir: Path) -> Path:
    path = Path(path_value).expanduser()
    if path.is_absolute():
        return path
    return (base_dir / path).resolve(strict=False)


def load_site_profile(path: Path) -> dict[str, Any]:
    profile = load_yaml(path)
    return require_map(profile, "site_profile")


def resolve_session_dir(
    profile: dict[str, Any],
    profile_path: Path,
    session_id: str | None,
    session_dir_arg: str | None,
) -> Path:
    if session_dir_arg:
        return resolve_relative(session_dir_arg, Path.cwd())

    data_inputs = require_map(profile.get("algorithm_data_inputs", {}), "algorithm_data_inputs")
    dataset_root_raw = data_inputs.get("dataset_root")
    if not isinstance(dataset_root_raw, str) or not dataset_root_raw:
        raise ValueError("缺少 algorithm_data_inputs.dataset_root。")

    dataset_root = resolve_relative(dataset_root_raw, profile_path.parent)
    if session_id:
        return dataset_root / session_id
    return dataset_root


def resolve_dataset_index(
    profile: dict[str, Any],
    profile_path: Path,
    session_dir: Path,
    dataset_index_arg: str | None,
) -> Path:
    if dataset_index_arg:
        return resolve_relative(dataset_index_arg, Path.cwd())

    data_inputs = require_map(profile.get("algorithm_data_inputs", {}), "algorithm_data_inputs")
    index_name = data_inputs.get("dataset_index_name", "dataset_index.yaml")
    if not isinstance(index_name, str) or not index_name:
        raise ValueError("algorithm_data_inputs.dataset_index_name 必须是非空字符串。")

    index_path = Path(index_name).expanduser()
    if index_path.is_absolute():
        return index_path
    return (session_dir / index_path).resolve(strict=False)


def resolve_output_path(
    profile: dict[str, Any],
    profile_path: Path,
    session_dir: Path,
    session_id: str | None,
    output_arg: str | None,
) -> Path:
    if output_arg:
        return resolve_relative(output_arg, Path.cwd())
    data_inputs = require_map(profile.get("algorithm_data_inputs", {}), "algorithm_data_inputs")
    ros_params_file = data_inputs.get("ros_params_file")
    if isinstance(ros_params_file, str) and ros_params_file:
        output_value = ros_params_file
        if session_id:
            output_value = output_value.replace("{session_id}", session_id)
            output_value = output_value.replace("session_xxx", session_id)
        if "replace_with" not in output_value and "session_xxx" not in output_value:
            return resolve_relative(output_value, profile_path.parent)
    return (session_dir / "site_data_input.yaml").resolve(strict=False)


def main() -> int:
    args = parse_args()
    profile_path = Path(args.site_profile).expanduser().resolve(strict=False)
    profile = load_site_profile(profile_path)
    session_dir = resolve_session_dir(profile, profile_path, args.session_id, args.session_dir)
    dataset_index_path = resolve_dataset_index(profile, profile_path, session_dir, args.dataset_index)
    output_path = resolve_output_path(profile, profile_path, session_dir, args.session_id, args.output)

    index = load_yaml(dataset_index_path)
    output = build_ros_params(
        dataset_index_path,
        index,
        str(session_dir),
        not args.no_index_reference,
    )
    validate_output(output, strict=not args.no_strict)

    output_path.parent.mkdir(parents=True, exist_ok=True)
    output_path.write_text(
        yaml.safe_dump(output, sort_keys=False, allow_unicode=True),
        encoding="utf-8",
    )

    print(f"已完成会话数据输入收尾：{output_path}")
    print(f"启动参数：data_input_params_file:={output_path}")
    return 0


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