/*********************************************************************
 *
 * Software License Agreement (BSD License)
 *
 * Nạp và tra cứu MissionSourceAdapter theo schema.
 *
 * Author: DuongTD
 *********************************************************************/
#ifndef MISSION_ADAPTERS_PLUGIN_REGISTRY_H_
#define MISSION_ADAPTERS_PLUGIN_REGISTRY_H_

#include <functional>
#include <map>
#include <string>
#include <vector>

#include <robot/node_handle.h>

#include <mission_adapters/adapter.h>

namespace mission_adapters
{
    /**
     * @class PluginRegistry
     * @brief Bảng tra schema -> adapter, nạp từ YAML bằng Boost.DLL.
     *
     * Cấu hình mong đợi (xem `pnkx_nav_core/config/mission_adapters_params.yaml`):
     *
     * @code{.yaml}
     * mission_adapters:
     *   mission_sources:
     *     - {name: goal_src,    type: GoalSourceAdapter}
     *     - {name: vda5050_src, type: VDA5050SourceAdapter}
     *
     * GoalSourceAdapter:
     *   library_path: libmission_adapters_goal_source
     * @endcode
     *
     * Khoá `library_path` là thứ hay bị quên nhất: thiếu nó thì plugin build xong vẫn báo "không
     * tìm thấy" lúc chạy. Registry vì thế báo lỗi nêu đích danh khoá bị thiếu thay vì chỉ nói
     * không nạp được.
     */
    class PluginRegistry
    {
    public:
        PluginRegistry() = default;
        ~PluginRegistry();

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

        /**
         * @brief Nạp toàn bộ nguồn khai trong `<ns>/mission_sources`.
         * @param nh NodeHandle gốc.
         * @param ns Namespace chứa danh sách nguồn.
         * @return false nếu có bất kỳ nguồn nào không nạp được. Các nguồn còn lại vẫn được đăng ký,
         *         và mỗi lỗi được log kèm lý do cụ thể.
         */
        bool loadFromConfig(robot::NodeHandle& nh, const std::string& ns = "mission_adapters");

        /**
         * @brief Đăng ký một adapter đã dựng sẵn (test, hoặc nguồn biên dịch thẳng vào host).
         * @return false nếu adapter null, schema rỗng, hoặc schema đã có chủ.
         */
        bool registerAdapter(const MissionSourceAdapter::Ptr& adapter);

        /// @brief Tìm adapter xử lý schema này. nullptr nếu không có.
        MissionSourceAdapter* find(const std::string& schema) const;

        size_t size() const { return adapters_.size(); }

        /// @brief Danh sách schema đã đăng ký, dùng cho log và test.
        std::vector<std::string> schemas() const;

        void clear();

    private:
        /// Nạp một nguồn. Trả false kèm log lý do nếu hỏng ở bất kỳ bước nào.
        bool loadOne(const std::string& name, const std::string& type, robot::NodeHandle& nh);

        std::map<std::string, MissionSourceAdapter::Ptr> adapters_;

        /**
         * Giữ factory của Boost.DLL sống đúng bằng vòng đời registry.
         *
         * Đây không phải biến thừa: factory nắm shared_library bên trong, thả nó ra là .so bị unload
         * trong khi các adapter tạo từ nó vẫn còn sống — vtable trỏ vào vùng nhớ đã gỡ.
         */
        std::vector<std::function<MissionSourceAdapter::Ptr()>> factories_;
    };

} // namespace mission_adapters

#endif  // MISSION_ADAPTERS_PLUGIN_REGISTRY_H_
