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

#ifndef COMPONENTS_H
#define COMPONENTS_H
#include <glm/ext/matrix_transform.hpp>
#include <Hazel/Renderer/Camera.h>
#include <Hazel/Renderer/ScenceCamera.h>

#include "ScriptableEntity.h"
#include "glm/glm.hpp"

namespace Hazel
{
    struct TransformComponent
    {
        glm::vec3 Translation{0.0f};
        glm::vec3 Rotation{0.0f};
        glm::vec3 Scale{1.0f};

        TransformComponent()                          = default;
        TransformComponent(const TransformComponent&) = default;

        TransformComponent(const glm::vec3& translation) : Translation(translation)
        {
        }

        glm::mat4 GetTransform() const
        {
            glm::mat4 rotation = glm::rotate(glm::mat4(1.0f), Rotation.x, glm::vec3(1.0f, 0.0f, 0.0f))
                                * glm::rotate(glm::mat4(1.0f), Rotation.y, glm::vec3(0.0f, 1.0f, 0.0f))
                                * glm::rotate(glm::mat4(1.0f), Rotation.z, glm::vec3(0.0f, 0.0f, 1.0f));

            return glm::translate(glm::mat4(1.0f), Translation) * rotation * glm::scale(glm::mat4(1.0f), Scale);
        }

    };

    struct SpriteRendererComponent
    {
        glm::vec4 Color{1.0f, 1.0f, 1.0f, 1.0f};

        SpriteRendererComponent()                          = default;
        SpriteRendererComponent(const SpriteRendererComponent&) = default;

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

    struct TagComponent
    {
        std::string Tag;

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


    struct CameraComponent
    {
        ScenceCamera Camera;
        bool Primary = true;    //TODO: 考虑多相机如何同步, 考虑移至Scence中
        bool FixedAspectRatio = false;
        CameraComponent()                          = default;
        CameraComponent(const CameraComponent&) = default;
    };

    struct NativeScriptComponent
    {
        ScriptableEntity* Instance = nullptr;


        ScriptableEntity* (*InstantiateScript)();
        void (*DestroyScript)(NativeScriptComponent*);

        template<typename T>
        void Bind()
        {
            InstantiateScript = []() { return static_cast<ScriptableEntity*>(new T()); };
            DestroyScript = [](NativeScriptComponent* nsc) { delete nsc->Instance; nsc->Instance = nullptr; };
        }
    };
}


#endif //COMPONENTS_H
