/**
 * @file trajectory_o6_task_cli_config.h
 * @brief RM75 轨迹与 LinkerHand O6 抓握任务命令行参数解析接口。
 *
 * @author 唐永康
 * @date 2026-07-11
 *
 * @details
 * 本文件只声明集成任务入口所需的结构化参数。参数解析与硬件连接、轨迹加载、
 * O6 通信和运动执行完全分离，因此可以在不连接任何设备的单元测试中验证。
 *
 * @dependencies
 * - rm_control/common/result.h
 *
 * @note
 * 默认运行模式为 DryRun。`--live` 只表达操作者意图，不能单独授权真实运动。
 */
#pragma once

#include "rm_control/common/result.h"

#include <array>
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <iosfwd>

namespace rm_control::config {

inline constexpr std::size_t kLinkerHandO6JointCount = 6;

/**
 * @brief LinkerHand O6 在 RM75 工具 RS-485 总线上的设备侧别。
 *
 * @reason 将命令行中的 `right|left` 映射集中为强类型，避免入口层散落设备地址魔法数字。
 *
 * @author 唐永康
 * @date 2026-07-11
 *
 * @safety 该枚举只保存地址，不访问总线，也不触发手部动作。
 * @note 当前工程约定右手地址为 0x27，左手地址为 0x28。
 */
enum class O6HandSide : std::uint8_t {
    Right = 0x27,
    Left = 0x28,
};

/**
 * @brief RM75 轨迹与 O6 抓握集成任务的命令行解析结果。
 *
 * @reason 把轨迹来源、节拍、双程序槽、低速参数、O6 姿态、速度、转矩和真实运动意图
 *         集中传给应用层，使入口无需重新解释字符串，也不会因危险默认值进入执行流程。
 *
 * @author 唐永康
 * @date 2026-07-11
 *
 * @safety `live_requested` 默认 false；后续硬件执行仍必须通过完整安全门控。
 * @note `grip_pose`、`grip_speed` 和 `grip_torque` 均为必填的 O6 六关节协议值，
 *       每个值的闭区间为 0..255；解析器不会为这些动作参数提供可执行默认值。
 */
struct TrajectoryO6TaskCliConfig {
    bool help_requested = false;                ///< 是否仅请求帮助文本。
    bool live_requested = false;                ///< 是否显式传入 `--live`，默认 DryRun。
    std::filesystem::path trajectory_path;      ///< 只读厂商轨迹源文件路径。
    int sample_period_ms = 0;                   ///< 轨迹采样周期，单位毫秒，范围 1..1000。
    int origin_speed_percent = 5;               ///< 回到轨迹原点速度比例，范围 1..10。
    int plan_speed_percent = 5;                 ///< 轨迹规划速度比例，范围 1..10。
    int program_id = 1;                         ///< 厂商轨迹规划程序编号，范围 1..100。
    bool return_from_trajectory_end = false;    ///< 是否先从原轨迹末点沿反向轨迹返回首点。
    int return_program_id = 0;                  ///< 反向返回程序编号；0 表示返回模式未启用。
    O6HandSide o6_side = O6HandSide::Right;     ///< O6 侧别，默认右手地址 0x27。
    /// O6 六关节抓握姿态。
    std::array<std::uint8_t, kLinkerHandO6JointCount> grip_pose{};
    /// O6 六关节抓握速度，必须由命令行显式提供。
    std::array<std::uint8_t, kLinkerHandO6JointCount> grip_speed{};
    /// O6 六关节抓握转矩，必须由命令行显式提供。
    std::array<std::uint8_t, kLinkerHandO6JointCount> grip_torque{};
    std::filesystem::path safety_config_path;   ///< 真实执行所需静态安全配置路径。
};

/**
 * @brief 打印 RM75 轨迹与 O6 抓握任务的命令行使用说明。
 *
 * @reason 集中维护必填参数、默认低速值和真实运动警示，防止入口错误分支的说明漂移。
 *
 * @author 唐永康
 * @date 2026-07-11
 *
 * @param[in] program_name 当前进程名，可以为空指针或空字符串。
 * @param[out] out 接收使用说明的输出流。
 * @return 无返回值。
 *
 * @calls 仅调用标准输出流，不读取轨迹、配置文件或设备状态。
 * @safety 本函数不连接 RM75 或 O6，不触发真实硬件动作。
 * @note 命令行规则变化时必须同步更新本函数和解析单元测试。
 */
void PrintTrajectoryO6TaskUsage(const char *program_name, std::ostream &out);

/**
 * @brief 解析 RM75 轨迹与 O6 抓握任务命令行参数。
 *
 * @reason 在加载轨迹和连接设备前严格验证全部外部输入，确保缺少必填项、超范围值
 *         或非法 O6 姿态、速度、转矩时保持 fail-closed。
 *
 * @author 唐永康
 * @date 2026-07-11
 *
 * @param[in] argc 命令行参数数量，必须为非负数。
 * @param[in] argv 命令行参数数组；`argc > 0` 时不能为空。
 * @return 成功时返回完整 `TrajectoryO6TaskCliConfig`；失败时返回带参数上下文的错误信息。
 *
 * @calls 仅调用标准库字符串、数值和路径构造函数，不调用厂商 SDK。
 * @safety 默认 `live_requested=false`；本函数不会执行轨迹、连接设备或写入源轨迹。
 * @note `--return-from-trajectory-end` 与 `--return-program-id` 必须成对出现，且返回程序号
 *       必须与正向 `--program-id` 不同；其余必填项在 `-h|--help` 模式下豁免。
 */
common::Result<TrajectoryO6TaskCliConfig>
ParseTrajectoryO6TaskCliArguments(int argc, char **argv);

} // namespace rm_control::config
