#ifndef COMPONENTS_HPP
#define COMPONENTS_HPP

#include "open_engine/scene/native_scriptable_entity.hpp"
#include "open_engine/scene/scene_camera.hpp"
#include "open_engine/renderer/texture.hpp"

#include <glm/ext/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/fwd.hpp>
#include <glm/glm.hpp>

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/quaternion.hpp>

#include <imgui_internal.h>
#include <imgui.h>
#include <string>

namespace OpenEngine {

    struct TagComponent
    {
        std::string tag;

        TagComponent() = default;
        TagComponent(const TagComponent&) = default;
        TagComponent(const std::string& tag)
            : tag(tag) {}
    };

    struct TransformComponent 
    {
        glm::vec3 translation = { 0.0f, 0.0f, 0.0f };
        glm::vec3 rotation = { 0.0f, 0.0f, 0.0f };
        glm::vec3 scale = { 1.0f, 1.0f, 1.0f };

        TransformComponent() = default;
        TransformComponent(const TransformComponent&) = default;
        TransformComponent(const glm::vec3& position)
            : translation(position) {}
    };

    glm::mat4 GetTransformFromComp(TransformComponent& transform_comp);

    struct SpriteRendererComponent 
    {
        glm::vec4 color{ 1.0f, 1.0f, 1.0f, 1.0f };
        Ref<Texture2D> texture;
        float tiling_factor = 1.0f;

        SpriteRendererComponent() = default;
        SpriteRendererComponent(const SpriteRendererComponent&) = default;
        SpriteRendererComponent(const glm::vec4& color)
            : color(color) {}
    };

    struct CameraComponent 
    {
        SceneCamera camera;
        bool primary = true;
        bool fixed_aspect_ratio = false;

        CameraComponent() = default;
        CameraComponent(const CameraComponent&) = default;
    };

    struct NativeScriptComponent 
    {
        NativeScriptableEntity* instance = nullptr;

        NativeScriptableEntity* (*InstanciateScript)();
        void (*DestroyInstanceScript)(NativeScriptComponent*);

        void OnImGuiRender(Entity& entity) 
        {};

        template <typename T>
            void Bind()
            {
                InstanciateScript = []() { return static_cast<NativeScriptableEntity*>(new T()); };
                DestroyInstanceScript = [](NativeScriptComponent* nsc)
                {
                    (delete nsc->instance);
                    nsc->instance = nullptr;
                };
            }
    };

}

#endif // COMPONENTS_HPP
