#pragma once

#include <memory>
#include <string>
#include <vector>
#include <functional>

#include <QString>

class QMenu;

namespace Xybrid::Data {
    class Node;
    class Graph;
}

namespace Xybrid::Config {
    class PluginInfo {
    public:
        QString id;
        std::vector<QString> oldIds;
        QString displayName;
        QString category;
        std::function<std::shared_ptr<Data::Node>()> createInstance;
        bool hidden = false;

        PluginInfo() = default;
        virtual ~PluginInfo() = default;
    };

    namespace PluginRegistry {
        std::shared_ptr<PluginInfo> enqueueRegistration(std::function<void()>);
        void registerPlugin(std::shared_ptr<PluginInfo>);
        void init();

        std::shared_ptr<Data::Node> createInstance(const QString& id);
        void populatePluginMenu(QMenu*, std::function<void(std::shared_ptr<Data::Node>)>, Data::Graph* = nullptr);
    }
}

#define RegisterPlugin(NAME, ...) \
    namespace { std::shared_ptr<Xybrid::Config::PluginInfo> _regInfo_##NAME = Xybrid::Config::PluginRegistry::enqueueRegistration([] { \
    auto i = std::make_shared<Xybrid::Config::PluginInfo>();\
    i->createInstance = []{ return std::make_shared<NAME>(); };\
    __VA_ARGS__ \
    Xybrid::Config::PluginRegistry::registerPlugin(i); }); }
