//
// Created by sfd on 25-5-28.
//

#ifndef ENTITY_H
#define ENTITY_H
#include <Hazel/Core/Log.h>

#include "Scene.h"



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


        template<typename T, typename... Args>
        T& AddComponent(Args&&... args)
        {
            if (HasComponent<T>())
            {
                HZ_CORE_WARN("Entity already has this Component!");
                assert(false);
            }
            T& component = m_Scene->m_Registry.emplace<T>(m_EntityHandle, std::forward<Args>(args)...);
            m_Scene->OnComponentAdded<T>(*this, component);
            return component;
        }

        template<typename T>
        T& GetComponent()
        {
            if (!HasComponent<T>())
            {
                HZ_CORE_ERROR("Entity has no component!");
                assert(-1);
            }
            return m_Scene->m_Registry.get<T>(m_EntityHandle);
        }


        template<typename T>
        void RemoveComponent() const
        {
            if (!HasComponent<T>())
            {
                HZ_CORE_WARN("Entity has no component!");
                return;
            }
            m_Scene->m_Registry.remove<T>(m_EntityHandle);
        }

        template<typename T>
        bool HasComponent() const
        {
            if (auto entity = m_Scene->m_Registry.try_get<T>(m_EntityHandle))
            {
                return true;
            }
            return false;
        }

        explicit operator bool() const { return m_EntityHandle != entt::null; }
        explicit operator uint32_t() const { return static_cast<uint32_t>(m_EntityHandle); }
        operator entt::entity() const { return m_EntityHandle; }

        bool operator==(const Entity& other) const { return m_EntityHandle == other.m_EntityHandle && m_Scene == other.m_Scene; }
        bool operator!=(const Entity& other) const { return !(*this==other); }

    private:
        entt::entity m_EntityHandle{ entt::null };
        Scene* m_Scene = nullptr;

    };
}


#endif //ENTITY_H
