// GENERATED FILE - do not edit by hand
// Generated by src/scripts/gen_robot_config.py
#ifndef BRAIN_ROBOT_CONFIG_HPP_
#define BRAIN_ROBOT_CONFIG_HPP_

#include <yaml-cpp/yaml.h>
#include <cstddef>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>
#include <vector>
#include <ament_index_cpp/get_package_share_directory.hpp>

namespace brain { namespace robot_config {

// Represents a single entry parsed from robot_config.yaml.
struct Entry {
  std::string name;
  std::unordered_map<std::string, std::string> fields;
};

// Pair type for config + params entries
struct BtConfigParam {
  std::string config;
  std::string param;
};

// Loader and query interface for robot configuration.
class RobotConfig {
 public:
  RobotConfig(std::string path = "") {
    if (path.empty()) {
      LoadFromFile(ament_index_cpp::get_package_share_directory("brain") + std::string("/config/robot_config.yaml"));
    } else {
      LoadFromFile(path);
    }
  }
  // Parse YAML from a file path. Returns true on success.
  bool LoadFromFile(const std::string& path) {
    entries_.clear();
    YAML::Node root = YAML::LoadFile(path);
    if (!root || !root.IsSequence()) { return false; }
    for (const auto& node : root) {
      if (!node.IsMap()) { continue; }
      Entry e;
      auto name_it = node["name"];
      if (name_it && name_it.IsScalar()) { e.name = name_it.as<std::string>(); }
      for (auto it = node.begin(); it != node.end(); ++it) {
        const auto key = it->first.as<std::string>();
        if (key == "name") { continue; }
        if (it->second) {
          if (it->second.IsScalar()) {
            e.fields.emplace(key, it->second.as<std::string>());
          } else {
            e.fields.emplace(key, YAML::Dump(it->second));
          }
        }
      }
      if (!e.name.empty()) { entries_.emplace_back(std::move(e)); }
    }
    return true;
  }

  // Return pointer to an Entry with matching name or nullptr if not found.
  const Entry* Find(const std::string& name) const {
    for (const auto& e : entries_) { if (e.name == name) return &e; }
    return nullptr;
  }

  // List all entry names.
  std::vector<std::string> Names() const {
    std::vector<std::string> out; out.reserve(entries_.size());
    for (const auto& e : entries_) out.push_back(e.name);
    return out;
  }

  // Generic value getter by name and key.
  std::optional<std::string> GetValue(const std::string& name, const std::string& key) const {
    const Entry* e = Find(name); if (!e) return std::nullopt;
    auto it = e->fields.find(key);
    if (it == e->fields.end()) return std::nullopt;
    return it->second;
  }

  std::optional<std::string> Version(const std::string& name) const {
    return GetValue(name, "version");
  }

  std::optional<std::string> SkillFile(const std::string& name) const {
    return GetValue(name, "skill_file");
  }

  std::optional<std::vector<BtConfigParam>> ConfigParamsPath(const std::string& name) const {
    auto v = GetValue(name, "config_params_path");
    if (!v) return std::nullopt;
    try {
      YAML::Node n = YAML::Load(*v);
      if (n.IsSequence()) {
        std::vector<BtConfigParam> res;
        for (const auto & it : n) {
          BtConfigParam p;
          if (it["config"] && it["config"].IsScalar()) p.config = it["config"].as<std::string>();
          if (it["param"] && it["param"].IsScalar()) p.param = it["param"].as<std::string>();
          res.push_back(std::move(p));
        }
        return res;
      }
    } catch (...) {}
    return std::nullopt;
  }

 private:
  std::vector<Entry> entries_;
};

}} // namespace robot_config; } // namespace brain

#endif  // BRAIN_ROBOT_CONFIG_HPP_
