#pragma once

#include "rm_control/interfaces/dexterous_hand.h"

namespace flight_robot::linker_hand {

/**
 * @brief 通过 RM75 工具端 Modbus RTU 实现 O6 统一灵巧手接口。
 *
 * @reason 将 O6 功能码、寄存器地址、方向和安全值校验集中在厂商适配边界，业务状态机只依赖
 *         IDexterousHand，且不会接触 RM_API2 类型。
 *
 * @author 唐永康
 * @date 2026-07-11
 *
 * @calls IToolModbusBus 的状态、输入/保持寄存器读取和保持寄存器写入能力。
 * @safety ReadReadiness 只读；CommandMotion 可能触发真实 O6 运动并必须受上层门控。
 * @note 协议字段来源为 `docs/O6机械手485协议简要说明.xlsx`，当前只支持 O6 六自由度手。
 */
class LinkerHandAdapter final : public rm_control::interfaces::IDexterousHand {
public:
    /**
     * @brief 构造指定左右手的 O6 工具端 Modbus 适配器。
     *
     * @reason 左右手决定从站地址和 identity direction，构造时固定可防止运行中错误切换设备。
     *
     * @author 唐永康
     * @date 2026-07-10
     *
     * @param tool_bus 已由 Application 注入的 RM75 工具端总线；适配器不拥有该对象。
     * @param side 目标 O6 手侧；Right 对应 0x27/'R'，Left 对应 0x28/'L'。
     * @return 构造函数无显式返回值。
     *
     * @calls 不访问总线，首次通信发生在 ReadReadiness 或 CommandMotion。
     * @safety 构造过程不触发硬件通信或运动。
     * @note tool_bus 生命周期必须长于本适配器。
     */
    LinkerHandAdapter(
        rm_control::interfaces::IToolModbusBus &tool_bus,
        rm_control::interfaces::DexterousHandSide side);

    LinkerHandAdapter(const LinkerHandAdapter &) = delete;
    LinkerHandAdapter &operator=(const LinkerHandAdapter &) = delete;
    LinkerHandAdapter(LinkerHandAdapter &&) = delete;
    LinkerHandAdapter &operator=(LinkerHandAdapter &&) = delete;

    /**
     * @brief 销毁 O6 协议适配器。
     *
     * @reason 适配器只借用总线引用，因此析构不应改变工具电压、通信模式或手部姿态。
     *
     * @author 唐永康
     * @date 2026-07-10
     *
     * @return 析构函数无返回值且不抛出异常。
     *
     * @calls 不调用总线或厂商接口。
     * @safety 不触发硬件动作，也不自动断电或松手。
     * @note 总线资源由其所有者负责清理。
     */
    ~LinkerHandAdapter() noexcept override = default;

    /**
     * @brief 读取并验证当前 O6 的工具总线和全部 readiness 输入寄存器。
     *
     * @reason 适配器集中执行 O6 地址、身份方向、六自由度、位置、转矩、速度、温度和
     *         故障规则，使上层只接收完整合规的 readiness，而不会误用部分读取结果。
     *
     * @author 唐永康
     * @date 2026-07-11
     *
     * @return 全部读取与校验成功时返回 `ready=true` 的快照；否则返回首个带上下文的失败。
     *
     * @calls IToolModbusBus::GetStatus 和 IToolModbusBus::ReadInputRegister。
     * @safety 仅使用功能码 04 读取状态，不触发 O6 或 RM75 运动。
     * @note 不自动重试；调用方不得把失败前读取的部分字段作为安全门控依据。
     */
    rm_control::common::Result<rm_control::interfaces::DexterousHandReadiness>
    ReadReadiness() override;

    /**
     * @brief 按转矩、速度、最后位置的顺序下发 O6 FC16 动作命令。
     *
     * @reason O6 的 FC04 地址返回实时转矩和实时速度，并不是 FC16 命令回读；因此只校验
     *         三组命令范围和每次 FC16 返回码，动作后的实际位置由上层 ReadReadiness 确认。
     *
     * @author 唐永康
     * @date 2026-07-11
     *
     * @param command 六关节位置、速度和转矩命令，每项有效范围 0..255；调用期间只读。
     * @return 全部输入合规且三次 FC16 写入均成功时成功，否则返回首个错误。
     *
     * @calls IToolModbusBus::WriteHoldingRegisters。
     * @safety 可能立即触发真实 O6 动作，只能在上层 Live、安全限制和操作者确认门控后调用。
     * @note 不读取 readiness 且不自动重试；转矩或速度任一步失败时不会下发位置。
     */
    rm_control::common::Result<void> CommandMotion(
        const rm_control::interfaces::O6MotionCommand &command) override;

private:
    rm_control::interfaces::IToolModbusBus &tool_bus_;
    rm_control::interfaces::DexterousHandSide side_;
};

} // namespace flight_robot::linker_hand
