#pragma once
#include <functional>
#include <nlohmann/json.hpp>
#include <nlohmann/json_fwd.hpp>
#include "dinkyecs.hpp"


#define ENROLL_COMPONENT(COMPONENT, ...)                                     \
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(COMPONENT, __VA_ARGS__);   \
    template <> struct NameOf<COMPONENT> {                                       \
      static constexpr const char *name = #COMPONENT;                            \
    };

namespace components {
  using namespace nlohmann;

  template <typename T> struct NameOf;

  using ReflFuncSignature = std::function<void(DinkyECS::World& world, DinkyECS::Entity ent, nlohmann::json &j)>;
  using ComponentMap = std::unordered_map<std::string, ReflFuncSignature>;

  template<typename COMPONENT> COMPONENT convert(nlohmann::json &data) {
    COMPONENT result;
    from_json(data, result);
    return result;
  }

  template <typename COMPONENT> void enroll(ComponentMap &m) {
    m[NameOf<COMPONENT>::name] = [](DinkyECS::World& world, DinkyECS::Entity ent, nlohmann::json &j) {
      COMPONENT c;
      from_json(j, c);
      world.set<COMPONENT>(ent, c);
    };
  }

  void configure_entity(const ComponentMap& component_map, DinkyECS::World& world, DinkyECS::Entity ent, json& data);
}
