#ifndef CF_PLUGIN_LOADER_H
#define CF_PLUGIN_LOADER_H

#include <string>
#include <unordered_map>
#include <vector>

#include "cf_step_abi.h"

namespace cf {

struct PluginError {
  std::string message;
};

class PluginRegistry {
 public:
  bool load_from_directory(const std::string& directory, std::string& error, bool recursive = false);
  bool load_from_directories(const std::vector<std::string>& directories, std::string& error, bool recursive = false);
  const CfStepVTable* resolve_step(const std::string& step_iri, std::string& error);
  size_t loaded_plugin_count() const;
  size_t loaded_step_count() const;
  std::string plugin_path_for_step(const std::string& step_iri) const;

 private:
  struct PluginEntry {
    void* handle = nullptr;
    std::string path;
    size_t (*list_fn)(const char*** out_step_iris) = nullptr;
    int (*resolve_fn)(const char* step_iri, CfStepVTable* out) = nullptr;
    std::vector<std::string> step_iris;
  };

  std::vector<PluginEntry> plugins_;
  std::unordered_map<std::string, CfStepVTable> vtables_;
  std::unordered_map<std::string, size_t> step_to_plugin_;
};

}  // namespace cf

#endif
