#!/usr/bin/env python3
"""Shared helpers for simulation profiles."""

from __future__ import annotations

from pathlib import Path
from typing import Any

import yaml


PROJECT_ROOT = Path(__file__).resolve().parents[3]
DEFAULT_PROFILE = PROJECT_ROOT / "src" / "deployment" / "profiles" / "sim_workshop.yaml"


def load_profile(profile_path: str | Path | None = None) -> dict[str, Any]:
    path = Path(profile_path).expanduser().resolve() if profile_path else DEFAULT_PROFILE
    if not path.exists():
        raise FileNotFoundError(f"未找到仿真 profile: {path}")

    with path.open("r", encoding="utf-8") as fp:
        profile = yaml.safe_load(fp) or {}

    if not isinstance(profile, dict):
        raise ValueError(f"profile 顶层必须是 dict: {path}")
    if profile.get("mode") != "sim":
        raise ValueError(f"profile mode 必须是 sim，当前为: {profile.get('mode')!r}")
    return profile


def get_nested(data: dict[str, Any], path: str, default: Any = None) -> Any:
    current: Any = data
    for part in path.split("."):
        if not isinstance(current, dict) or part not in current:
            return default
        current = current[part]
    return current


def require_nested(data: dict[str, Any], path: str) -> Any:
    value = get_nested(data, path)
    if value is None:
        raise KeyError(f"profile 缺少字段: {path}")
    return value


def repo_path(value: str | Path) -> Path:
    path = Path(value).expanduser()
    return path if path.is_absolute() else PROJECT_ROOT / path


def as_int(value: Any, field_name: str) -> int:
    try:
        return int(value)
    except (TypeError, ValueError) as exc:
        raise ValueError(f"{field_name} 必须是整数，当前为: {value!r}") from exc


def as_float(value: Any, field_name: str) -> float:
    try:
        return float(value)
    except (TypeError, ValueError) as exc:
        raise ValueError(f"{field_name} 必须是数字，当前为: {value!r}") from exc


def validate_sim_profile(profile: dict[str, Any]) -> None:
    required_fields = [
        "vehicle_id",
        "workshop_pc.gateway.vehicle_host",
        "workshop_pc.gateway.vehicle_port",
        "vehicle_agent.private_cmd_vel_topic",
        "isaac.scene_script",
        "isaac.scene_manifest_path",
        "isaac.cmd_vel_topic",
        "safety.max_speed_mps",
    ]
    for field in required_fields:
        require_nested(profile, field)

    scene_script = repo_path(require_nested(profile, "isaac.scene_script"))
    if not scene_script.exists():
        raise FileNotFoundError(f"Isaac 场景脚本不存在: {scene_script}")

    agent_topic = require_nested(profile, "vehicle_agent.private_cmd_vel_topic")
    isaac_topic = require_nested(profile, "isaac.cmd_vel_topic")
    if agent_topic != isaac_topic:
        raise ValueError(
            "vehicle_agent.private_cmd_vel_topic 必须与 isaac.cmd_vel_topic 一致，"
            f"当前为 {agent_topic!r} vs {isaac_topic!r}"
        )

    vehicle_port = as_int(require_nested(profile, "workshop_pc.gateway.vehicle_port"), "vehicle_port")
    if not 1 <= vehicle_port <= 65535:
        raise ValueError(f"vehicle_port 超出端口范围: {vehicle_port}")

    max_speed = as_float(require_nested(profile, "safety.max_speed_mps"), "safety.max_speed_mps")
    if max_speed <= 0.0:
        raise ValueError("safety.max_speed_mps 必须大于 0")
