#ifndef ENTITY_HPP
#define ENTITY_HPP

#include "open_engine/core.hpp"

#include "open_engine/scene/scene.hpp"

#include <cstdint>
#include <entt/entity/fwd.hpp>
#include <entt/entt.hpp>
#include <utility>

namespace OpenEngine {
    class Entity
    {
        public:
            Entity() = default;
            Entity(entt::entity handle, Scene* scene);
            Entity(const Entity& other) = default;

            template<typename T, typename ... Args>
                T& AddComponents(Args&&... args)
                {
                    OE_ASSERT(!HasComponent<T>(), "Entity already has component.");

                    T& component = scene->registry.emplace<T>(handle, std::forward<Args>(args)...);
                    scene->OnComponentAdded(*this, component);
                    return component;
                };

            template<typename T, typename ... Args>
                T& GetComponents(Args&&... args)
                {
                    OE_ASSERT(HasComponent<T>(), "Entity doesn't have component.");
                    return scene->registry.get<T>(handle);
                };

            template<typename T>
                void RemoveComponents()
                {
                    OE_ASSERT(HasComponent<T>(), "Entity doesn't have component.");
                    scene->registry.remove<T>(handle);
                };

            template<typename T>
                bool HasComponent()
                {
                    return scene->registry.all_of<T>(handle);
                };

            operator bool() const { return handle != entt::null; };
            operator entt::entity() const { return handle; };
            operator uint32_t() const { return (uint32_t)handle; };

            bool operator ==(const Entity& other) const {
                return handle == other.handle && scene == other.scene;
            };

            bool operator !=(const Entity& other) const {
                return !operator==(other);
            };

        private:
            entt::entity handle { entt::null };
            OpenEngine::Scene* scene = nullptr;

    };
}

#endif // ENTITY_HPP
