using System.Text.Json;
using Flyshot.ControllerClientCompat;
using Microsoft.AspNetCore.Mvc;

namespace Flyshot.Server.Host.Controllers;

/// <summary>
/// 提供对 `flyshot-uaes-interface` 既有 FastAPI HTTP 路由层的一比一 MVC 兼容控制器。
/// </summary>
[ApiController]
[Tags("ControllerClient 兼容")]
public sealed class LegacyHttpApiController : ControllerBase
{
    private readonly IControllerClientCompatService _compatService;
    private readonly ILogger<LegacyHttpApiController> _logger;

    /// <summary>
    /// 初始化旧 HTTP 兼容控制器。
    /// </summary>
    /// <param name="compatService">ControllerClient 兼容服务。</param>
    /// <param name="logger">日志记录器。</param>
    public LegacyHttpApiController(IControllerClientCompatService compatService, ILogger<LegacyHttpApiController> logger)
    {
        _compatService = compatService ?? throw new ArgumentNullException(nameof(compatService));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    /// <summary>
    /// 兼容旧根路径探活接口。
    /// </summary>
    /// <returns>旧 HTTP 服务约定的 Hello World 响应。</returns>
    [HttpGet("/")]
    public IActionResult Root()
    {
        return Ok(new { message = "Hello World" });
    }

    /// <summary>
    /// 兼容旧 `/connect_server/` 路由；在 replacement 宿主中仅记录调用方期望连接的地址。
    /// </summary>
    /// <param name="server_ip">旧客户端传入的服务端 IP。</param>
    /// <param name="port">旧客户端传入的服务端端口。</param>
    /// <returns>与旧 FastAPI 层一致的状态响应。</returns>
    [HttpPost("/connect_server/")]
    public IActionResult ConnectServer([FromQuery] string server_ip, [FromQuery] int port)
    {
        _logger.LogInformation("ConnectServer 调用: server_ip={ServerIp}, port={Port}", server_ip, port);
        try
        {
            _compatService.ConnectServer(server_ip, port);
            _logger.LogInformation("ConnectServer 成功: server_ip={ServerIp}, port={Port}", server_ip, port);
            return Ok(new { status = "connected" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "ConnectServer 失败: server_ip={ServerIp}, port={Port}", server_ip, port);
            return LegacyBadRequest("Connect Server failed");
        }
    }

    /// <summary>
    /// 兼容旧 `GetServerVersion` 版本查询语义。
    /// </summary>
    /// <returns>服务端版本号。</returns>
    [HttpGet("/get_server_version/")]
    public IActionResult GetServerVersion()
    {
        return Ok(new { server_version = _compatService.GetServerVersion() });
    }

    /// <summary>
    /// 兼容旧 `GetClientVersion` 版本查询语义。
    /// </summary>
    /// <returns>客户端版本号。</returns>
    [HttpGet("/get_client_version/")]
    public IActionResult GetClientVersion()
    {
        return Ok(new { client_version = _compatService.GetClientVersion() });
    }

    /// <summary>
    /// 兼容旧 `/setup_robot/` 路由。
    /// </summary>
    /// <param name="robot_name">旧 HTTP 层使用的机器人名称。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/setup_robot/")]
    public IActionResult SetupRobot([FromQuery] string robot_name)
    {
        _logger.LogInformation("SetupRobot 调用: robot_name={RobotName}", robot_name);
        try
        {
            _compatService.SetUpRobot(robot_name);
            _logger.LogInformation("SetupRobot 成功: robot_name={RobotName}", robot_name);
            return Ok(new { status = "robot setup" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "SetupRobot 失败: robot_name={RobotName}", robot_name);
            return LegacyBadRequest("SetUpRobot failed");
        }
    }

    /// <summary>
    /// 兼容旧 `SetUpRobotFromEnv(env_file)` 参数形状。
    /// </summary>
    /// <param name="env_file">环境文件路径。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/setup_robot_from_env/")]
    public IActionResult SetupRobotFromEnv([FromQuery] string env_file)
    {
        try
        {
            _compatService.SetUpRobotFromEnv(env_file);
            return Ok(new { status = "robot setup" });
        }
        catch
        {
            return LegacyBadRequest("SetUpRobotFromEnv failed");
        }
    }

    /// <summary>
    /// 兼容旧 `SetShowTCP(is_show, axis_length, axis_size)` 参数形状。
    /// </summary>
    /// <param name="is_show">是否显示 TCP。</param>
    /// <param name="axis_length">坐标轴长度。</param>
    /// <param name="axis_size">坐标轴线宽。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/set_show_tcp/")]
    public IActionResult SetShowTcp(
        [FromQuery] bool is_show = true,
        [FromQuery] double axis_length = 0.1,
        [FromQuery] int axis_size = 2)
    {
        try
        {
            _compatService.SetShowTcp(is_show, axis_length, axis_size);
            return Ok(new { status = "show TCP set" });
        }
        catch
        {
            return LegacyBadRequest("SetShowTCP failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/is_setup/` 路由。
    /// </summary>
    /// <returns>当前机器人是否完成初始化。</returns>
    [HttpGet("/is_setup/")]
    public IActionResult IsSetup()
    {
        return Ok(new { is_setup = _compatService.IsSetUp });
    }

    /// <summary>
    /// 兼容旧 `EnableRobot(buffer_size=4)` 参数形状。
    /// </summary>
    /// <param name="buffer_size">控制器执行缓冲区大小。</param>
    /// <returns>旧 FastAPI 层风格的布尔状态响应。</returns>
    [HttpGet("/enable_robot/")]
    public IActionResult EnableRobot([FromQuery] int buffer_size = 4)
    {
        _logger.LogInformation("EnableRobot 调用: buffer_size={BufferSize}", buffer_size);
        try
        {
            _compatService.EnableRobot(buffer_size);
            _logger.LogInformation("EnableRobot 成功");
            return Ok(new { enable_robot = true });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "EnableRobot 失败");
            return LegacyBadRequest("EnableRobot failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/disable_robot/` 路由。
    /// </summary>
    /// <returns>旧 FastAPI 层风格的布尔状态响应。</returns>
    [HttpGet("/disable_robot/")]
    public IActionResult DisableRobot()
    {
        _logger.LogInformation("DisableRobot 调用");
        try
        {
            _compatService.DisableRobot();
            _logger.LogInformation("DisableRobot 成功");
            return Ok(new { disable_robot = true });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "DisableRobot 失败");
            return LegacyBadRequest("DisableRobot failed");
        }
    }

    /// <summary>
    /// 提供与旧客户端 <c>StopMove</c> 语义对应的 HTTP 端点。
    /// </summary>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpGet("/stop_move/")]
    public IActionResult StopMove()
    {
        _logger.LogInformation("StopMove 调用");
        try
        {
            _compatService.StopMove();
            _logger.LogInformation("StopMove 成功");
            return Ok(new { status = "move stopped" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "StopMove 失败");
            return LegacyBadRequest("StopMove failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/set_active_controller/` 路由。
    /// </summary>
    /// <param name="sim">是否切到仿真控制器。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/set_active_controller/")]
    public IActionResult SetActiveController([FromQuery] bool sim)
    {
        _logger.LogInformation("SetActiveController 调用: sim={Sim}", sim);
        try
        {
            _compatService.SetActiveController(sim);
            _logger.LogInformation("SetActiveController 成功: sim={Sim}", sim);
            return Ok(new { status = "active controller set" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "SetActiveController 失败: sim={Sim}", sim);
            return LegacyBadRequest("SetActiveController failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/connect_robot/` 路由。
    /// </summary>
    /// <param name="ip">控制器 IP。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/connect_robot/")]
    public IActionResult ConnectRobot([FromQuery] string ip)
    {
        _logger.LogInformation("ConnectRobot 调用: ip={Ip}", ip);
        try
        {
            _compatService.Connect(ip);
            _logger.LogInformation("ConnectRobot 成功: ip={Ip}", ip);
            return Ok(new { status = "robot connected" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "ConnectRobot 失败: ip={Ip}", ip);
            return LegacyBadRequest("Connect failed");
        }
    }

    /// <summary>
    /// 提供与旧客户端 <c>Disconnect</c> 语义对应的 HTTP 端点。
    /// </summary>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/disconnect_robot/")]
    public IActionResult DisconnectRobot()
    {
        _logger.LogInformation("DisconnectRobot 调用");
        try
        {
            _compatService.Disconnect();
            _logger.LogInformation("DisconnectRobot 成功");
            return Ok(new { status = "robot disconnected" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "DisconnectRobot 失败");
            return LegacyBadRequest("Disconnect failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/robot_info/` 路由。
    /// </summary>
    /// <returns>旧 HTTP 层聚合的机器人元信息。</returns>
    [HttpGet("/robot_info/")]
    public IActionResult GetRobotInfo()
    {
        try
        {
            return Ok(new
            {
                name = _compatService.GetRobotName(),
                server_version = _compatService.ServerVersion,
                dof = _compatService.GetDegreesOfFreedom(),
                speed_ratio = _compatService.GetSpeedRatio()
            });
        }
        catch
        {
            return LegacyBadRequest("GetRobotInfo failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/set_tcp/` 路由。
    /// </summary>
    /// <param name="tcp_data">三维 TCP 请求体。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/set_tcp/")]
    public IActionResult SetTcp([FromBody] LegacyTcpRequest tcp_data)
    {
        _logger.LogInformation("SetTcp 调用: x={X}, y={Y}, z={Z}", tcp_data.x, tcp_data.y, tcp_data.z);
        try
        {
            _compatService.SetTcp(tcp_data.x, tcp_data.y, tcp_data.z);
            _logger.LogInformation("SetTcp 成功");
            return Ok(new { status = "TCP set" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "SetTcp 失败");
            return LegacyBadRequest("SetTCP failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/get_tcp/` 路由。
    /// </summary>
    /// <returns>当前 TCP 三维坐标。</returns>
    [HttpGet("/get_tcp/")]
    public IActionResult GetTcp()
    {
        try
        {
            return Ok(new { tcp = _compatService.GetTcp() });
        }
        catch
        {
            return LegacyBadRequest("GetTCP failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/set_io/` 路由。
    /// </summary>
    /// <param name="port">IO 端口号。</param>
    /// <param name="value">IO 值。</param>
    /// <param name="io_type">IO 类型字符串。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/set_io/")]
    public IActionResult SetIo([FromQuery] int port, [FromQuery] bool value, [FromQuery] string io_type)
    {
        _logger.LogInformation("SetIo 调用: port={Port}, value={Value}, io_type={IoType}", port, value, io_type);
        try
        {
            _compatService.SetIo(port, value, io_type);
            _logger.LogInformation("SetIo 成功: port={Port}, value={Value}", port, value);
            return Ok(new { status = "IO set" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "SetIo 失败: port={Port}, value={Value}", port, value);
            return LegacyBadRequest("SetDigitalOutput failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/get_io/` 路由。
    /// </summary>
    /// <param name="port">IO 端口号。</param>
    /// <param name="io_type">IO 类型字符串。</param>
    /// <returns>当前 IO 值。</returns>
    [HttpGet("/get_io/")]
    public IActionResult GetIo([FromQuery] int port, [FromQuery] string io_type)
    {
        _logger.LogInformation("GetIo 调用: port={Port}, io_type={IoType}", port, io_type);
        try
        {
            var value = _compatService.GetIo(port, io_type);
            _logger.LogInformation("GetIo 成功: port={Port}, value={Value}", port, value);
            return Ok(new { value });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "GetIo 失败: port={Port}", port);
            return LegacyBadRequest("GetDigitalOutput failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/get_joint_position/` 路由。
    /// </summary>
    /// <returns>旧 HTTP 层定义的关节位置 JSON 外形。</returns>
    [HttpGet("/get_joint_position/")]
    public IActionResult GetJointPosition()
    {
        try
        {
            return Ok(new { success = true, points = _compatService.GetJointPositions() });
        }
        catch
        {
            return LegacyBadRequest("GetJointPosition failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/move_joint/` 路由。
    /// </summary>
    /// <param name="joint_data">关节位置请求体。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/move_joint/")]
    public IActionResult MoveJoint([FromBody] LegacyJointPositionRequest joint_data)
    {
        _logger.LogInformation("MoveJoint 调用: 关节数={JointCount}", joint_data.joints.Count);
        _logger.LogDebug("MoveJoint 路点: {Joints}", string.Join(", ", joint_data.joints.Select(j => j.ToString("F4"))));
        try
        {
            _compatService.MoveJoint(joint_data.joints);
            _logger.LogInformation("MoveJoint 成功");
            return Ok(new { status = "robot moved" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "MoveJoint 失败");
            return LegacyBadRequest("MoveJoint failed");
        }
    }

    /// <summary>
    /// 以直角坐标 `[x,y,z,w,p,r]` 执行点到点移动。
    /// </summary>
    /// <param name="pose_data">直角位姿请求体。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/move_pose/")]
    public IActionResult MovePose([FromBody] JsonElement pose_data)
    {
        try
        {
            var poseRequest = LegacyCartesianPoseRequest.FromJson(pose_data);
            var pose = poseRequest.ToPoseArray();
            _logger.LogInformation("MovePose 调用: x={X}, y={Y}, z={Z}, w={W}, p={P}, r={R}",
                poseRequest.x, poseRequest.y, poseRequest.z, poseRequest.w, poseRequest.p, poseRequest.r);

            _compatService.MovePose(pose);
            _logger.LogInformation("MovePose 成功");
            return Ok(new { status = "robot moved" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "MovePose 失败");
            return LegacyBadRequest("MovePose failed");
        }
    }

    /// <summary>
    /// 兼容旧 `GetNearestIK(pose, seed, ik)` 参数形状。
    /// </summary>
    /// <param name="request">IK 请求体。</param>
    /// <returns>IK 结果。</returns>
    [HttpPost("/get_nearest_ik/")]
    public IActionResult GetNearestIk([FromBody] LegacyNearestIkRequest request)
    {
        try
        {
            return Ok(new { success = true, ik = _compatService.GetNearestIk(request.pose, request.seed) });
        }
        catch (NotSupportedException exception)
        {
            return StatusCode(StatusCodes.Status501NotImplemented, new { detail = exception.Message });
        }
        catch
        {
            return LegacyBadRequest("GetNearestIK failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/list_flyShotTraj/` 路由。
    /// </summary>
    /// <returns>已上传飞拍轨迹名称列表。</returns>
    [HttpGet("/list_flyShotTraj/")]
    public IActionResult ListFlyshotTrajectories()
    {
        var names = _compatService.ListTrajectoryNames();
        if (names.Count == 0)
        {
            return LegacyBadRequest("ListFlyShotTraj failed");
        }

        return Ok(new { flyshot_trajs = names });
    }

    /// <summary>
    /// 兼容旧 `/execute_trajectory/` 路由，并接受两种历史请求体形状。
    /// </summary>
    /// <param name="waypoints">轨迹请求体。</param>
    /// <param name="method">查询字符串中的 method 覆盖值（兼容历史调用方式）。</param>
    /// <param name="save_traj">查询字符串中的 save_traj 覆盖值（兼容历史调用方式）。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/execute_trajectory/")]
    public IActionResult ExecuteTrajectory(
        [FromBody] JsonElement waypoints,
        [FromQuery] string? method = null,
        [FromQuery] bool? save_traj = null)
    {
        _logger.LogInformation("ExecuteTrajectory 调用: method={Method}, save_traj={SaveTraj}", method ?? "icsp", save_traj ?? false);
        try
        {
            var request = ParseExecuteTrajectoryRequest(waypoints, method, save_traj);
            _logger.LogDebug("ExecuteTrajectory 路点数={WaypointCount}, method={Method}", request.Waypoints.Count, request.Method);
            _compatService.ExecuteTrajectory(
                request.Waypoints,
                new TrajectoryExecutionOptions(request.Method, request.SaveTrajectory));
            _logger.LogInformation("ExecuteTrajectory 成功: method={Method}", request.Method);
            return Ok(new { status = "trajectory executed" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "ExecuteTrajectory 失败");
            return LegacyBadRequest("ExecuteTrajectory failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/upload_flyshot/` 路由。
    /// </summary>
    /// <param name="trajectory_data">飞拍上传请求体。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/upload_flyshot/")]
    public IActionResult UploadFlyshot([FromBody] LegacyFlightTrajectoryRequest trajectory_data)
    {
        _logger.LogInformation(
            "UploadFlyshot 调用: name={Name}, waypoints={WaypointCount}, shot_flags={ShotCount}",
            trajectory_data.name,
            trajectory_data.waypoints.Count,
            trajectory_data.shot_flags.Count(static f => f));

        if (trajectory_data.shot_flags.Count != trajectory_data.waypoints.Count)
        {
            _logger.LogWarning("UploadFlyshot 校验失败: shot_flags长度({ShotFlagsCount}) != 路点数({WaypointCount})",
                trajectory_data.shot_flags.Count, trajectory_data.waypoints.Count);
            return LegacyValidationError("shot_flags长度必须与路点数量相同");
        }

        if (trajectory_data.offset_values.Count != trajectory_data.waypoints.Count)
        {
            _logger.LogWarning("UploadFlyshot 校验失败: offset_values长度({OffsetCount}) != 路点数({WaypointCount})",
                trajectory_data.offset_values.Count, trajectory_data.waypoints.Count);
            return LegacyValidationError("offset_values长度必须与路点数量相同");
        }

        if (trajectory_data.addrs.Count != trajectory_data.waypoints.Count)
        {
            _logger.LogWarning("UploadFlyshot 校验失败: addrs长度({AddrCount}) != 路点数({WaypointCount})",
                trajectory_data.addrs.Count, trajectory_data.waypoints.Count);
            return LegacyValidationError("addrs长度必须与路点数量相同");
        }

        try
        {
            var trajectory = new ControllerClientCompatUploadedTrajectory(
                name: trajectory_data.name,
                waypoints: trajectory_data.waypoints,
                shotFlags: trajectory_data.shot_flags,
                offsetValues: trajectory_data.offset_values.Select(static value => (int)value),
                addressGroups: trajectory_data.addrs);

            _compatService.UploadTrajectory(trajectory);
            _logger.LogInformation("UploadFlyshot 成功: name={Name}", trajectory_data.name);
            return Ok(new { status = "FlyShot uploaded" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "UploadFlyshot 失败: name={Name}", trajectory_data.name);
            return LegacyBadRequest("UploadFlyShotTraj failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/execute_flyshot/` 路由。
    /// </summary>
    /// <param name="data">包含轨迹名称和执行参数的请求体。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/execute_flyshot/")]
    public IActionResult ExecuteFlyshot([FromBody] LegacyExecuteFlyshotRequest data)
    {
        _logger.LogInformation(
            "ExecuteFlyshot 调用: name={Name}, method={Method}, move_to_start={MoveToStart}, use_cache={UseCache}, wait={Wait}",
            data.name, data.method, data.move_to_start, data.use_cache, data.wait);
        try
        {
            _compatService.ExecuteTrajectoryByName(
                data.name,
                new FlyshotExecutionOptions(
                    moveToStart: data.move_to_start,
                    method: data.method,
                    saveTrajectory: data.save_traj,
                    useCache: data.use_cache,
                    wait: data.wait));
            _logger.LogInformation("ExecuteFlyshot 成功: name={Name}", data.name);
            return Ok(new { status = "FlyShot executed", success = true });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "ExecuteFlyshot 失败: name={Name}", data.name);
            return StatusCode(StatusCodes.Status500InternalServerError, new { detail = exception.Message });
        }
    }

    /// <summary>
    /// 兼容旧 `SaveTrajInfo(name, method)` 参数形状。
    /// </summary>
    /// <param name="request">轨迹保存请求体。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/save_traj_info/")]
    public IActionResult SaveTrajectoryInfo([FromBody] LegacyTrajectoryInfoRequest request)
    {
        _logger.LogInformation("SaveTrajectoryInfo 调用: name={Name}, method={Method}", request.name, request.method);
        try
        {
            _compatService.SaveTrajectoryInfo(request.name, request.method);
            _logger.LogInformation("SaveTrajectoryInfo 成功: name={Name}", request.name);
            return Ok(new { status = "trajectory info saved", success = true });
        }
        catch (NotSupportedException exception)
        {
            _logger.LogWarning(exception, "SaveTrajectoryInfo 不支持: name={Name}", request.name);
            return StatusCode(StatusCodes.Status501NotImplemented, new { detail = exception.Message });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "SaveTrajectoryInfo 失败: name={Name}", request.name);
            return LegacyBadRequest("SaveTrajInfo failed");
        }
    }

    /// <summary>
    /// 兼容旧 `IsFlyShotTrajValid(time, name, method, save_traj)` 参数形状。
    /// </summary>
    /// <param name="request">轨迹有效性检查请求体。</param>
    /// <returns>有效性和轨迹时长。</returns>
    [HttpPost("/is_flyShotTrajValid/")]
    public IActionResult IsFlyshotTrajectoryValid([FromBody] LegacyFlyshotValidationRequest request)
    {
        _logger.LogInformation("IsFlyshotTrajectoryValid 调用: name={Name}, method={Method}", request.name, request.method);
        try
        {
            var isValid = _compatService.IsFlyshotTrajectoryValid(
                out var duration,
                request.name,
                request.method,
                request.save_traj);

            _logger.LogInformation("IsFlyshotTrajectoryValid 结果: name={Name}, valid={Valid}, duration={Duration}s", request.name, isValid, duration.TotalSeconds);
            return Ok(new { success = isValid, valid = isValid, time = duration.TotalSeconds });
        }
        catch (NotSupportedException exception)
        {
            _logger.LogWarning(exception, "IsFlyshotTrajectoryValid 不支持: name={Name}", request.name);
            return StatusCode(StatusCodes.Status501NotImplemented, new { detail = exception.Message });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "IsFlyshotTrajectoryValid 失败: name={Name}", request.name);
            return LegacyBadRequest("IsFlyShotTrajValid failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/set_speedRatio/` 路由。
    /// </summary>
    /// <param name="data">速度倍率请求体。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/set_speedRatio/")]
    public IActionResult SetSpeedRatio([FromBody] LegacySpeedRatioRequest data)
    {
        _logger.LogInformation("SetSpeedRatio 调用: speed={Speed}", data.speed);
        try
        {
            // 验证数值 范围符合预期（例如 0.01到 1.0），以避免对控制器造成潜在风险
            if (data.speed < 0.01 || data.speed > 1.0)
            {
                _logger.LogWarning("SetSpeedRatio 参数无效: speed={Speed}", data.speed);
                return BadRequest(new { detail = "Speed ratio must be between 0.01 and 1.0." });
            }

            _compatService.SetSpeedRatio(data.speed);
            _logger.LogInformation("SetSpeedRatio 成功: speed={Speed}", data.speed);
            return Ok(new { message = "set_speedRatio executed", returnCode = 0 });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "SetSpeedRatio 失败: speed={Speed}", data.speed);
            return LegacyBadRequest("set_speedRatio failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/delete_flyshot/` 路由。
    /// </summary>
    /// <param name="request">包含轨迹名称的请求体。</param>
    /// <returns>旧 FastAPI 层风格的状态响应。</returns>
    [HttpPost("/delete_flyshot/")]
    public IActionResult DeleteFlyshot([FromBody] LegacyNameRequest request)
    {
        _logger.LogInformation("DeleteFlyshot 调用: name={Name}", request.name);
        try
        {
            _compatService.DeleteTrajectory(request.name);
            _logger.LogInformation("DeleteFlyshot 成功: name={Name}", request.name);
            return Ok(new { status = "FlyShot deleted" });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "DeleteFlyshot 失败: name={Name}", request.name);
            return LegacyBadRequest("DeleteFlyShotTraj failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/init_mpc_robt` 路由，保留历史拼写。
    /// </summary>
    /// <param name="data">初始化请求体。</param>
    /// <returns>旧 FastAPI 层风格的初始化结果。</returns>
    [HttpPost("/init_mpc_robt")]
    public IActionResult InitMpcRobot([FromBody] LegacyInitMpcRobotRequest data)
    {
        _logger.LogInformation(
            "InitMpcRobot 调用: robot_name={RobotName}, robot_ip={RobotIp}, sim={Sim}, server={ServerIp}:{Port}",
            data.robot_name, data.robot_ip, data.sim, data.server_ip, data.port);
        try
        {
           
            _compatService.SetUpRobot(data.robot_name);
            if (!_compatService.IsSetUp)
            {
                _logger.LogWarning("InitMpcRobot 失败: Robot not setup");
                return LegacyBadRequest("Robot not setup");
            }

            _compatService.SetActiveController(data.sim);
            _compatService.Connect(data.robot_ip);
            _compatService.EnableRobot(8);
            _logger.LogInformation("InitMpcRobot 成功: robot_name={RobotName}", data.robot_name);
            return Ok(new { message = "init_Success", returnCode = 0 });
        }
        catch (Exception exception)
        {
            _logger.LogError(exception, "InitMpcRobot 失败");
            return LegacyBadRequest("Connect Server failed");
        }
    }

    /// <summary>
    /// 兼容旧 `/get_pose` 路由。
    /// </summary>
    /// <returns>当前末端位姿数组。</returns>
    [HttpGet("/get_pose")]
    public IActionResult GetPose()
    {
        try
        {
            return Ok(new { pose = _compatService.GetPose() });
        }
        catch
        {
            return LegacyBadRequest("GetPose failed");
        }
    }

    /// <summary>
    /// 解析旧 `/execute_trajectory/` 的完整参数形状。
    /// </summary>
    /// <param name="payload">原始 JSON 请求体。</param>
    /// <param name="queryMethod">查询字符串中的 method 覆盖值。</param>
    /// <param name="querySaveTrajectory">查询字符串中的 save_traj 覆盖值。</param>
    /// <returns>统一后的路点和执行参数。</returns>
    private static (
        IReadOnlyList<IReadOnlyList<double>> Waypoints,
        string Method,
        bool SaveTrajectory) ParseExecuteTrajectoryRequest(
            JsonElement payload,
            string? queryMethod,
            bool? querySaveTrajectory)
    {
        string method = queryMethod ?? "icsp";
        bool saveTrajectory = querySaveTrajectory ?? false;

        if (payload.ValueKind == JsonValueKind.Object)
        {
            if (payload.TryGetProperty("method", out var methodElement) && methodElement.ValueKind == JsonValueKind.String)
            {
                method = methodElement.GetString() ?? method;
            }

            if (payload.TryGetProperty("save_traj", out var saveTrajectoryElement))
            {
                saveTrajectory = saveTrajectoryElement.GetBoolean();
            }

            if (!payload.TryGetProperty("waypoints", out var waypointElement))
            {
                throw new InvalidOperationException("ExecuteTrajectory request body must include waypoints.");
            }

            return (ParseLegacyTrajectoryWaypoints(waypointElement), method, saveTrajectory);
        }

        return (ParseLegacyTrajectoryWaypoints(payload), method, saveTrajectory);
    }

    /// <summary>
    /// 解析旧 `/execute_trajectory/` 可能出现的两种历史请求体形状。
    /// </summary>
    /// <param name="waypoints">原始 JSON 请求体。</param>
    /// <returns>统一后的关节路点集合。</returns>
    private static IReadOnlyList<IReadOnlyList<double>> ParseLegacyTrajectoryWaypoints(JsonElement waypoints)
    {
        if (waypoints.ValueKind != JsonValueKind.Array)
        {
            throw new InvalidOperationException("ExecuteTrajectory request body must be an array.");
        }

        var parsedWaypoints = new List<IReadOnlyList<double>>();
        foreach (var waypointElement in waypoints.EnumerateArray())
        {
            if (waypointElement.ValueKind == JsonValueKind.Array)
            {
                parsedWaypoints.Add(waypointElement.EnumerateArray().Select(static value => value.GetDouble()).ToArray());
                continue;
            }

            if (waypointElement.ValueKind == JsonValueKind.Object && waypointElement.TryGetProperty("joints", out var jointElement))
            {
                parsedWaypoints.Add(jointElement.EnumerateArray().Select(static value => value.GetDouble()).ToArray());
                continue;
            }

            throw new InvalidOperationException("Unsupported waypoint payload shape.");
        }

        return parsedWaypoints;
    }

    /// <summary>
    /// 构造与旧 FastAPI `HTTPException(status_code=400, detail=...)` 等价的响应。
    /// </summary>
    /// <param name="detail">错误详情文本。</param>
    /// <returns>400 JSON 响应。</returns>
    private BadRequestObjectResult LegacyBadRequest(string detail)
    {
        return BadRequest(new { detail });
    }

    /// <summary>
    /// 构造与旧 FastAPI `422` 输入校验失败等价的响应。
    /// </summary>
    /// <param name="detail">错误详情文本。</param>
    /// <returns>422 JSON 响应。</returns>
    private ObjectResult LegacyValidationError(string detail)
    {
        return StatusCode(StatusCodes.Status422UnprocessableEntity, new { detail });
    }
}

/// <summary>
/// 表示旧 `/set_tcp/` 路由使用的三维 TCP 请求体。
/// </summary>
public sealed class LegacyTcpRequest
{
    /// <summary>
    /// 获取或设置 TCP X。
    /// </summary>
    public double x { get; init; }

    /// <summary>
    /// 获取或设置 TCP Y。
    /// </summary>
    public double y { get; init; }

    /// <summary>
    /// 获取或设置 TCP Z。
    /// </summary>
    public double z { get; init; }
}

/// <summary>
/// 表示旧 `/move_joint/` 路由使用的关节请求体。
/// </summary>
public sealed class LegacyJointPositionRequest
{
    /// <summary>
    /// 获取或设置目标关节数组。
    /// </summary>
    public List<double> joints { get; init; } = [];
}

/// <summary>
/// 表示 `/move_pose/` 路由使用的直角位姿请求体。
/// </summary>
public sealed class LegacyCartesianPoseRequest
{
    /// <summary>
    /// MovePose 第一版入口硬限制：TCP X/Y 最大绝对值，单位 mm。
    /// </summary>
    private const double MaxHorizontalMillimeters = 1000.0;

    /// <summary>
    /// MovePose 第一版入口硬限制：TCP Z 最小值，单位 mm。
    /// </summary>
    private const double MinZMillimeters = 0.0;

    /// <summary>
    /// MovePose 第一版入口硬限制：TCP Z 最大值，单位 mm。
    /// </summary>
    private const double MaxZMillimeters = 1200.0;

    /// <summary>
    /// MovePose 第一版入口硬限制：W/R 姿态角最大绝对值，单位 deg。
    /// </summary>
    private const double MaxRollYawDegrees = 180.0;

    /// <summary>
    /// MovePose 第一版入口硬限制：P 姿态角最大绝对值，单位 deg。
    /// </summary>
    private const double MaxPitchDegrees = 90.0;

    /// <summary>
    /// 获取或设置 TCP X，单位为 mm。
    /// </summary>
    public double x { get; init; }

    /// <summary>
    /// 获取或设置 TCP Y，单位为 mm。
    /// </summary>
    public double y { get; init; }

    /// <summary>
    /// 获取或设置 TCP Z，单位为 mm。
    /// </summary>
    public double z { get; init; }

    /// <summary>
    /// 获取或设置姿态 W，单位为 deg。
    /// </summary>
    public double w { get; init; }

    /// <summary>
    /// 获取或设置姿态 P，单位为 deg。
    /// </summary>
    public double p { get; init; }

    /// <summary>
    /// 获取或设置姿态 R，单位为 deg。
    /// </summary>
    public double r { get; init; }

    /// <summary>
    /// 从原始 JSON 请求体解析直角位姿，并显式拒绝缺字段、null 和非有限数。
    /// </summary>
    /// <param name="json">原始 JSON 请求体。</param>
    /// <returns>解析后的直角位姿请求。</returns>
    public static LegacyCartesianPoseRequest FromJson(JsonElement json)
    {
        if (json.ValueKind != JsonValueKind.Object)
        {
            throw new ArgumentException("MovePose request body must be an object.");
        }

        // 旧接口要求请求体必须完整提供 x/y/z/w/p/r，不能让模型绑定把缺字段静默补 0。
        return new LegacyCartesianPoseRequest
        {
            x = ReadRequiredFiniteDouble(json, "x", -MaxHorizontalMillimeters, MaxHorizontalMillimeters),
            y = ReadRequiredFiniteDouble(json, "y", -MaxHorizontalMillimeters, MaxHorizontalMillimeters),
            z = ReadRequiredFiniteDouble(json, "z", MinZMillimeters, MaxZMillimeters),
            w = ReadRequiredFiniteDouble(json, "w", -MaxRollYawDegrees, MaxRollYawDegrees),
            p = ReadRequiredFiniteDouble(json, "p", -MaxPitchDegrees, MaxPitchDegrees),
            r = ReadRequiredFiniteDouble(json, "r", -MaxRollYawDegrees, MaxRollYawDegrees)
        };
    }

    /// <summary>
    /// 转换为兼容层使用的六维位姿数组。
    /// </summary>
    /// <returns>[x,y,z,w,p,r] 数组。</returns>
    public IReadOnlyList<double> ToPoseArray()
    {
        return [x, y, z, w, p, r];
    }

    /// <summary>
    /// 读取必填有限数值字段。
    /// </summary>
    /// <param name="json">请求体 JSON 对象。</param>
    /// <param name="propertyName">字段名。</param>
    /// <param name="minInclusive">允许的最小值。</param>
    /// <param name="maxInclusive">允许的最大值。</param>
    /// <returns>字段对应的有限 double 数值。</returns>
    private static double ReadRequiredFiniteDouble(
        JsonElement json,
        string propertyName,
        double minInclusive,
        double maxInclusive)
    {
        if (!json.TryGetProperty(propertyName, out var property) || property.ValueKind != JsonValueKind.Number)
        {
            throw new ArgumentException($"MovePose request field '{propertyName}' is required and must be a number.");
        }

        var value = property.GetDouble();
        if (double.IsNaN(value) || double.IsInfinity(value))
        {
            throw new ArgumentOutOfRangeException(propertyName, "MovePose request values must be finite.");
        }

        if (value < minInclusive || value > maxInclusive)
        {
            throw new ArgumentOutOfRangeException(
                propertyName,
                value,
                $"MovePose request field '{propertyName}' must be between {minInclusive} and {maxInclusive}.");
        }

        return value;
    }
}

/// <summary>
/// 表示旧 `/upload_flyshot/` 路由使用的飞拍上传请求体。
/// </summary>
public sealed class LegacyFlightTrajectoryRequest
{
    /// <summary>
    /// 获取或设置地址组集合。
    /// </summary>
    public List<List<int>> addrs { get; init; } = [];

    /// <summary>
    /// 获取或设置飞拍轨迹名称。
    /// </summary>
    public string name { get; init; } = string.Empty;

    /// <summary>
    /// 获取或设置偏移周期集合。
    /// </summary>
    public List<double> offset_values { get; init; } = [];

    /// <summary>
    /// 获取或设置拍照标志集合。
    /// </summary>
    public List<bool> shot_flags { get; init; } = [];

    /// <summary>
    /// 获取或设置关节路点集合。
    /// </summary>
    public List<List<double>> waypoints { get; init; } = [];
}

/// <summary>
/// 表示旧 `/execute_flyshot/` 与 `/delete_flyshot/` 路由使用的名称请求体。
/// </summary>
public sealed class LegacyNameRequest
{
    /// <summary>
    /// 获取或设置轨迹名称。
    /// </summary>
    public string name { get; init; } = string.Empty;
}

/// <summary>
/// 表示旧 `/execute_flyshot/` 路由使用的完整执行请求体。
/// </summary>
public sealed class LegacyExecuteFlyshotRequest
{
    /// <summary>
    /// 获取或设置轨迹名称。
    /// </summary>
    public string name { get; init; } = string.Empty;

    /// <summary>
    /// 获取或设置是否先移动到轨迹起点。
    /// </summary>
    public bool move_to_start { get; init; } = true;

    /// <summary>
    /// 获取或设置轨迹生成方法。
    /// </summary>
    public string method { get; init; } = "icsp";

    /// <summary>
    /// 获取或设置是否保存轨迹信息。
    /// </summary>
    public bool save_traj { get; init; } = true;

    /// <summary>
    /// 获取或设置是否复用轨迹缓存。
    /// </summary>
    public bool use_cache { get; init; } = true;

    /// <summary>
    /// 获取或设置是否等待机器人执行完整条飞拍轨迹后再返回。
    /// </summary>
    public bool wait { get; init; } = true;
}

/// <summary>
/// 表示旧 `SaveTrajInfo` 参数形状。
/// </summary>
public sealed class LegacyTrajectoryInfoRequest
{
    /// <summary>
    /// 获取或设置轨迹名称。
    /// </summary>
    public string name { get; init; } = string.Empty;

    /// <summary>
    /// 获取或设置轨迹生成方法。
    /// </summary>
    public string method { get; init; } = "icsp";
}

/// <summary>
/// 表示旧 `IsFlyShotTrajValid` 参数形状。
/// </summary>
public sealed class LegacyFlyshotValidationRequest
{
    /// <summary>
    /// 获取或设置轨迹名称。
    /// </summary>
    public string name { get; init; } = string.Empty;

    /// <summary>
    /// 获取或设置轨迹生成方法。
    /// </summary>
    public string method { get; init; } = "icsp";

    /// <summary>
    /// 获取或设置是否保存轨迹信息。
    /// </summary>
    public bool save_traj { get; init; } = true;
}

/// <summary>
/// 表示旧 `GetNearestIK` 参数形状。
/// </summary>
public sealed class LegacyNearestIkRequest
{
    /// <summary>
    /// 获取或设置目标位姿 `[x,y,z,qx,qy,qz,qw]`。
    /// </summary>
    public List<double> pose { get; init; } = [];

    /// <summary>
    /// 获取或设置 IK seed 关节数组。
    /// </summary>
    public List<double> seed { get; init; } = [];
}

/// <summary>
/// 表示旧 `/set_speedRatio/` 路由使用的速度倍率请求体。
/// </summary>
public sealed class LegacySpeedRatioRequest
{
    /// <summary>
    /// 获取或设置目标速度倍率。
    /// </summary>
    public double speed { get; init; }
}

/// <summary>
/// 表示旧 `/init_mpc_robt` 路由使用的初始化请求体。
/// </summary>
public sealed class LegacyInitMpcRobotRequest
{
    /// <summary>
    /// 获取或设置目标服务端 IP。
    /// </summary>
    public string server_ip { get; init; } = string.Empty;

    /// <summary>
    /// 获取或设置目标服务端端口。
    /// </summary>
    public int port { get; init; }

    /// <summary>
    /// 获取或设置机器人名称。
    /// </summary>
    public string robot_name { get; init; } = string.Empty;

    /// <summary>
    /// 获取或设置机器人控制器 IP。
    /// </summary>
    public string robot_ip { get; init; } = string.Empty;

    /// <summary>
    /// 获取或设置是否使用仿真控制器；默认 false 连接真机。
    /// </summary>
    public bool sim { get; init; }
}
