#pragma once

#include "rm_control/interfaces/robot_arm.h"
#include "rm_control/interfaces/tool_modbus_bus.h"

#include <memory>

namespace flight_robot::realman {

/**
 * @brief 将统一机械臂接口映射到睿尔曼 RM_API2。
 *
 * @reason 使用 PImpl 隔离厂商 SDK 类型，确保业务层和兼容头不包含 rm_interface.h。
 *
 * @author 唐永康
 * @date 2026-07-10
 *
 * @calls RM_API2 连接、状态、运动、拖动示教和原生轨迹复现接口。
 * @safety 本类包含真实运动能力；调用方必须先通过上层安全门控。
 * @note 当前只支持七自由度 RM75-6F，不提供其他机械臂型号兼容承诺。
 */
class RealmanArmAdapter final : public rm_control::interfaces::IRobotArm,
                                public rm_control::interfaces::IToolModbusBus {
public:
    /**
     * @brief 构造未连接的睿尔曼适配器。
     * @reason PImpl 在构造期准备私有状态，同时不初始化 SDK 或连接设备。
     * @author 唐永康
     * @date 2026-07-10
     * @return 构造函数无返回值。
     * @calls 不调用厂商接口。
     * @safety 不触发运动或硬件通信。
     * @note 调用 connect 前所有硬件接口都会返回未连接错误。
     */
    RealmanArmAdapter();
    RealmanArmAdapter(const RealmanArmAdapter &) = delete;
    RealmanArmAdapter &operator=(const RealmanArmAdapter &) = delete;
    RealmanArmAdapter(RealmanArmAdapter &&) = delete;
    RealmanArmAdapter &operator=(RealmanArmAdapter &&) = delete;
    /**
     * @brief 析构适配器并释放可能存在的 SDK 连接。
     * @reason RAII 保证异常路径和提前返回路径不会泄漏厂商句柄。
     * @author 唐永康
     * @date 2026-07-10
     * @return 析构函数无返回值且不抛出异常。
     * @calls disconnect、厂商断开与 SDK 销毁接口。
     * @safety 只执行资源清理，不主动发送运动指令。
     * @note SDK 清理错误仅记录到标准错误流。
     */
    ~RealmanArmAdapter() noexcept override;

    /** @copydoc rm_control::interfaces::IRobotArm::connect */
    rm_control::common::Result<void>
    connect(const rm_control::common::RobotConnectionConfig &config) override;
    /** @copydoc rm_control::interfaces::IRobotArm::disconnect */
    void disconnect() override;
    /** @copydoc rm_control::interfaces::IRobotArm::isConnected */
    bool isConnected() const noexcept override;

    /** @copydoc rm_control::interfaces::IRobotArm::getRobotInfo */
    rm_control::common::Result<rm_control::common::RobotInfo> getRobotInfo() override;
    /** @copydoc rm_control::interfaces::IRobotArm::getRobotSoftwareInfo */
    rm_control::common::Result<rm_control::common::RobotSoftwareInfo>
    getRobotSoftwareInfo() override;
    /** @copydoc rm_control::interfaces::IRobotArm::getCurrentArmState */
    rm_control::common::Result<rm_control::common::ArmState> getCurrentArmState() override;
    /** @copydoc rm_control::interfaces::IRobotArm::getForceData */
    rm_control::common::Result<rm_control::common::ForceData> getForceData() override;
    /** @copydoc rm_control::interfaces::IRobotArm::getRobotSafetyStatus */
    rm_control::common::Result<rm_control::common::RobotSafetyStatus>
    getRobotSafetyStatus() override;
    /** @copydoc rm_control::interfaces::IRobotArm::getJointLimits */
    rm_control::common::Result<rm_control::common::RobotJointLimits>
    getJointLimits() override;

    /** @copydoc rm_control::interfaces::IRobotArm::moveJ */
    rm_control::common::Result<void> moveJ(const std::vector<float> &joints_deg,
                                           int speed_percent,
                                           int blend_radius,
                                           int trajectory_connect,
                                           bool blocking) override;
    /** @copydoc rm_control::interfaces::IRobotArm::moveL */
    rm_control::common::Result<void> moveL(const rm_control::common::Pose &pose,
                                           int speed_percent,
                                           int blend_radius,
                                           int trajectory_connect,
                                           bool blocking) override;

    /** @copydoc rm_control::interfaces::IRobotArm::startDragTeach */
    rm_control::common::Result<void>
    startDragTeach(const rm_control::common::DragTeachStartOptions &options) override;
    /** @copydoc rm_control::interfaces::IRobotArm::stopDragTeach */
    rm_control::common::Result<void> stopDragTeach() override;
    /** @copydoc rm_control::interfaces::IRobotArm::saveDragTeachTrajectory */
    rm_control::common::VendorTrajectorySaveAttempt
    saveDragTeachTrajectory(const std::filesystem::path &path) override;

    /** @copydoc rm_control::interfaces::IRobotArm::moveToDragTrajectoryOrigin */
    rm_control::common::Result<void> moveToDragTrajectoryOrigin(bool blocking) override;
    /** @copydoc rm_control::interfaces::IRobotArm::replayLastDragTrajectory */
    rm_control::common::Result<void> replayLastDragTrajectory(bool blocking) override;
    /** @copydoc rm_control::interfaces::IRobotArm::pauseDragTrajectoryReplay */
    rm_control::common::Result<void> pauseDragTrajectoryReplay() override;
    /** @copydoc rm_control::interfaces::IRobotArm::continueDragTrajectoryReplay */
    rm_control::common::Result<void> continueDragTrajectoryReplay() override;
    /** @copydoc rm_control::interfaces::IRobotArm::stopDragTrajectoryReplay */
    rm_control::common::Result<void> stopDragTrajectoryReplay() override;
    /** @copydoc rm_control::interfaces::IRobotArm::saveVendorDragTrajectoryProgram */
    rm_control::common::Result<void> saveVendorDragTrajectoryProgram(
        const rm_control::common::VendorDragTrajectoryExecutionRequest &request) override;
    /** @copydoc rm_control::interfaces::IRobotArm::runControllerProgram */
    rm_control::common::Result<void> runControllerProgram(
        const rm_control::common::ControllerProgramRunRequest &request) override;
    /** @copydoc rm_control::interfaces::IRobotArm::executeVendorDragTrajectoryFile */
    rm_control::common::Result<void> executeVendorDragTrajectoryFile(
        const rm_control::common::VendorDragTrajectoryExecutionRequest &request) override;
    /** @copydoc rm_control::interfaces::IRobotArm::getControllerProgramRunState */
    rm_control::common::Result<rm_control::common::ControllerProgramRunState>
    getControllerProgramRunState() override;
    /** @copydoc rm_control::interfaces::IRobotArm::slowStopMotion */
    rm_control::common::Result<void> slowStopMotion() override;
    /** @copydoc rm_control::interfaces::IRobotArm::isControllerProgramSlotAvailable */
    rm_control::common::Result<bool> isControllerProgramSlotAvailable(
        int controller_program_id) override;

    /** @copydoc rm_control::interfaces::IToolModbusBus::GetStatus */
    rm_control::common::Result<rm_control::interfaces::ToolModbusBusStatus>
    GetStatus() override;
    /** @copydoc rm_control::interfaces::IToolModbusBus::Configure */
    rm_control::common::Result<rm_control::interfaces::ToolModbusBusStatus>
    Configure(
        const rm_control::interfaces::ToolModbusBusConfiguration &configuration) override;
    /** @copydoc rm_control::interfaces::IToolModbusBus::ReadInputRegister */
    rm_control::common::Result<std::uint16_t> ReadInputRegister(
        std::uint8_t device_id,
        std::uint16_t address) override;
    /** @copydoc rm_control::interfaces::IToolModbusBus::ReadInputRegisters */
    rm_control::common::Result<std::vector<std::uint16_t>> ReadInputRegisters(
        std::uint8_t device_id,
        std::uint16_t start_address,
        std::size_t register_count) override;
    /** @copydoc rm_control::interfaces::IToolModbusBus::ReadHoldingRegisters */
    rm_control::common::Result<std::vector<std::uint16_t>> ReadHoldingRegisters(
        std::uint8_t device_id,
        std::uint16_t start_address,
        std::size_t register_count) override;
    /** @copydoc rm_control::interfaces::IToolModbusBus::WriteHoldingRegisters */
    rm_control::common::Result<void> WriteHoldingRegisters(
        std::uint8_t device_id,
        std::uint16_t start_address,
        const std::vector<std::uint16_t> &values) override;

private:
    class Implementation;
    std::unique_ptr<Implementation> implementation_;
};

} // namespace flight_robot::realman
