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

#ifndef COMPONENTS_H
#define COMPONENTS_H
#include <Hazel/Renderer/Camera.h>
#include <Hazel/Renderer/ScenceCamera.h>


#define GLM_ENABLE_EXPERIMENTAL
#include <glm/ext/matrix_transform.hpp>
#include <Hazel/Renderer/Texture.h>

#include "glm/glm.hpp"
#include "glm/gtx/quaternion.hpp"
#include <box2d/types.h>
#include <Hazel/Core/UUID.h>

namespace Hazel
{
    struct IDComponent
    {
        UUID ID;
        IDComponent() = default;
        IDComponent(const UUID& uuid) : ID(uuid) {}
        IDComponent(const IDComponent&) = default;
    };

    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));

            const glm::mat4 rotation = glm::toMat4(glm::quat(Rotation));

            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};
        Ref<Texture2D> Texture;
        float TilingFactor = 1.0f;

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

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

    struct CircleRendererComponent
    {
        glm::vec4 Color{1.0f, 1.0f, 1.0f, 1.0f};
        float Radius = 0.5f;
        float Thickness = 0.5f;
        float Fade = 0.005f;

        CircleRendererComponent() = default;
        CircleRendererComponent(const CircleRendererComponent&) = default;

        CircleRendererComponent(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;
    };

    // forward declaration
    class ScriptableEntity;
    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; };
        }
    };

    // Physics

    struct RigidBody2DComponent
    {
        enum class BodyType { Static = 0, Dynamic, Kinematic };

        BodyType Type = BodyType::Static;
        bool FixedRotation = false;

        // Storage for runtime
        b2BodyId RuntimeBody;

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

    struct BoxCollider2DComponent
    {
        glm::vec2 Offset = {0.0f, 0.0f};
        glm::vec2 Size = {0.5f, 0.5f};

        // TODO(Yan): move into material texture in the future
        float Density = 1.0f;                   // 密度
        float Friction = 0.5f;                  // 摩擦力
        float Restitution = 0.0f;               // 弹力
        float RestitutionThreshold = 0.5f;      // 弹力阈值

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

    struct CircleCollider2DComponent
    {
        glm::vec2 Offset = {0.0f, 0.0f};
        float Radius = 0.5f;

        // TODO(Yan): move into material texture in the future
        float Density = 1.0f;                   // 密度
        float Friction = 0.5f;                  // 摩擦力
        float Restitution = 0.0f;               // 弹力
        float RestitutionThreshold = 0.5f;      // 弹力阈值

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

    template<typename... Components>
    struct ComponentGroup
    {
    };
    using AllComponents =
        ComponentGroup<TransformComponent, SpriteRendererComponent,
                        CircleRendererComponent, BoxCollider2DComponent,
                        CircleCollider2DComponent, CameraComponent,
                        NativeScriptComponent, RigidBody2DComponent>;
}


#endif //COMPONENTS_H
