/**
 * @file json_runner_cli_config.cpp
 * @brief RM JSON 指令运行器命令行参数解析实现。
 *
 * @author mashiro
 * @date 2026-07-09
 * @last_modified 2026-07-09
 *
 * @details
 * 本文件实现 `rm_json_runner` 的参数解析。实现代码只处理 `argc/argv`，
 * 不读取 JSON 文件、不连接 RealMan SDK、不访问真实机械臂。这样可以把入口文件
 * 控制在依赖装配和流程启动范围内，也便于通过普通单元测试验证参数边界。
 *
 * 设计原则：
 * - 帮助、错误和正常参数路径都返回结构化结果；
 * - 不在解析函数中调用 `std::exit`；
 * - 不在解析函数中打印错误，错误文本交给调用方统一输出；
 * - 不改变原有命令行兼容性。
 *
 * @dependencies
 * - rm_control/config/json_runner_cli_config.h
 */
#include "rm_control/config/json_runner_cli_config.h"

#include <ostream>
#include <string>

namespace rm_control::config {
namespace {

/**
 * @brief 将可能为空的进程名转换为可显示文本。
 *
 * @author mashiro
 * @date 2026-07-09
 * @last_modified 2026-07-09
 *
 * @details
 * 命令行 usage 需要展示程序名，但测试或异常调用场景可能传入空指针。
 * 该函数集中处理空指针和空字符串，避免每个 usage 函数重复写保护逻辑。
 *
 * @param[in] program_name `main()` 传入的 `argv[0]`，允许为空指针。
 * @param[in] fallback_name 程序名不可用时使用的默认名称。
 *
 * @return 可安全打印的程序名字符串。
 *
 * @throws 本函数不主动抛出异常；字符串构造失败属于标准库内存异常。
 *
 * @note
 * 该函数不做路径裁剪，保留调用方传入的原始进程名。
 *
 * @warning
 * 不要在此函数中读取 `/proc` 或环境变量，避免 CLI 解析依赖运行环境。
 *
 * @thread_safety
 * 函数只读输入并返回局部对象，线程安全。
 *
 * @par 边界条件
 * `program_name == nullptr` 或 `program_name[0] == '\0'` 时返回 fallback。
 *
 * @par 后续维护
 * 如果多个 CLI 模块继续需要该逻辑，可再抽到公共 utils；当前保持局部以减少改动面。
 */
std::string SafeProgramName(const char *program_name, const char *fallback_name) {
    if (program_name == nullptr || program_name[0] == '\0') {
        return fallback_name;
    }
    return program_name;
}

} // namespace

void PrintJsonRunnerUsage(const char *program_name, std::ostream &out) {
    const std::string display_name = SafeProgramName(program_name, "rm_json_runner");
    out << "Usage: " << display_name << " <commands.json> [--validate-only]\n"
        << "\n"
        << "Examples:\n"
        << "  " << display_name << " ../config/sample_readonly.json --validate-only\n"
        << "  " << display_name << " ../config/sample_readonly.json\n"
        << "\n"
        << "Safety:\n"
        << "  JSON defaults should keep dry_run=true and allow_motion=false first.\n"
        << "  Set safety.dry_run=false and safety.allow_motion=true only after checking the target.\n";
}

common::Result<JsonRunnerCliConfig> ParseJsonRunnerCliArguments(int argc, char **argv) {
    JsonRunnerCliConfig config;
    if (argc == 2) {
        const std::string first_argument = argv[1] == nullptr ? "" : argv[1];
        if (first_argument == "-h" || first_argument == "--help") {
            config.help_requested = true;
            return common::Result<JsonRunnerCliConfig>::success(config);
        }
    }

    if (argc < 2 || argc > 3) {
        return common::Result<JsonRunnerCliConfig>::failure(
            "expected <commands.json> and optional --validate-only");
    }

    config.command_file_path = argv[1] == nullptr ? "" : argv[1];
    if (config.command_file_path.empty()) {
        return common::Result<JsonRunnerCliConfig>::failure("commands.json path must not be empty");
    }

    if (argc == 3) {
        const std::string option = argv[2] == nullptr ? "" : argv[2];
        if (option != "--validate-only") {
            return common::Result<JsonRunnerCliConfig>::failure("unknown option: " + option);
        }
        config.validate_only = true;
    }

    return common::Result<JsonRunnerCliConfig>::success(config);
}

} // namespace rm_control::config
