/*********************************************************************
 *
 * Software License Agreement (BSD License)
 *
 * Plugin Loader Helper for Boost.DLL
 * Maps symbol names (export names) to library file paths
 * Similar to plugins.xml but for boost::dll
 *********************************************************************/
#ifndef ROBOT_PLUGIN_LOADER_HELPER_H_
#define ROBOT_PLUGIN_LOADER_HELPER_H_

#include <string>
#include <vector>
#include <map>
#include <yaml-cpp/yaml.h>
#include <filesystem>
#include <robot/robot.h>

namespace robot
{

/**
 * @class PluginLoaderHelper
 * @brief Helper class to find library paths from symbol names (export names)
 * 
 * This class reads a YAML configuration file (similar to plugins.xml) that maps
 * symbol names (export names used in BOOST_DLL_ALIAS) to library file paths.
 * 
 * Usage:
 *   PluginLoaderHelper loader;
 *   std::string lib_path = loader.findLibraryPath("CustomPlanner");
 *   if (!lib_path.empty()) {
 *     // Use lib_path with boost::dll::import_alias
 *   }
 */
class PluginLoaderHelper
{
public:
  /**
   * @brief Constructor
   */
  PluginLoaderHelper();

  /**
   * @brief Constructor
   * @param nh NodeHandle to read parameters from
   * @param config_namespace Namespace in NodeHandle where plugins are stored (default: root)
   */
  PluginLoaderHelper(robot::NodeHandle nh, const std::string& config_namespace = "");

  /**
   * @brief Find library path from symbol name (export name)
   * @param symbol_name The export name (e.g., "CustomPlanner", "PNKXLocalPlanner")
   * @return Full path to the library file, or empty string if not found
   */
  std::string findLibraryPath(const std::string& symbol_name);

  /**
   * @brief Check if a symbol is registered
   * @param symbol_name The export name
   * @return True if symbol is found in config
   */
  bool hasSymbol(const std::string& symbol_name) const;

  /**
   * @brief Set NodeHandle and namespace for reading plugins
   * @param nh NodeHandle to read parameters from
   * @param config_namespace Namespace in NodeHandle where plugins are stored
   */
  void setNodeHandle(robot::NodeHandle nh, const std::string& config_namespace = "");

  /**
   * @brief Get all registered symbol names
   * @return Vector of all symbol names
   */
  std::vector<std::string> getRegisteredSymbols() const;

  /**
   * @brief Get build directory (CMAKE_BINARY_DIR) at runtime
   * @return Build directory path, or empty if not found
   */
  static std::string getBuildDirectory();

  /**
   * @brief Get workspace path at runtime
   * @return Workspace path (e.g., /home/robotics/AGV/Diff_Wheel_Prj/t800_v2_ws), or empty if not found
   */
  static std::string getWorkspacePath();

private:
  /**
   * @brief Resolve library path (absolute, then PNKX_NAV_CORE_LIBRARY_PATH, search_paths_, cwd)
   * @param library_path Path from config (may be relative or absolute)
   * @return Resolved absolute path, or empty if not found
   */
  std::string resolveLibraryPath(const std::string& library_path) const;

  robot::NodeHandle nh_;                    // NodeHandle to read parameters
  std::string config_namespace_;            // Namespace for plugins in NodeHandle
  std::vector<std::string> search_paths_;   // Search paths for libraries
};

} // namespace robot

#endif // ROBOT_PLUGIN_LOADER_HELPER_H_

