#pragma once
#include "DeerStudio/StudioAPI/GenericRefStructs.h"

#include "DeerRender/Mesh.h"
#include "DeerRender/Shader.h"
#include "DeerRender/Texture.h"

#include "glm/glm.hpp"
#include <stdint.h>
#include <string>

namespace Deer {
	namespace StudioAPI {
		struct EntityStruct;
		extern EntityStruct activeEntity;

		struct EntityStruct : EntityHandleStruct {
			EntityStruct(uint16_t entId = 0, int32_t envId = -1);

			std::string getName();
			void setName(std::string&);

			int getId();
			bool exists();

			bool isRoot();
			void destroy();

			EntityHandleStruct createChild(std::string&);

			void setParent(EntityHandleStruct parent);
			EntityHandleStruct getParent();

			bool isDescendantOf(EntityHandleStruct parent);
			bool opEquals(const EntityHandleStruct& other);

			// COMPONENTS
			EntityHandleStruct getMeshComponent();
			EntityHandleStruct createMeshComponent();
			bool hasMeshComponent();
			void removeMeshComponent();

			EntityHandleStruct getShaderComponent();
			EntityHandleStruct createShaderComponent();
			bool hasShaderComponent();
			void removeShaderComponent();

			EntityHandleStruct getCameraComponent();
			EntityHandleStruct createCameraComponent();
			bool hasCameraComponent();
			void removeCameraComponent();

			// This function can be adapted to get a specific transform since
			// the data is the same
			EntityHandleStruct getSelf();
		};

		struct EntityChildArrayStruct : EntityHandleStruct {
			int getChildCount();
			EntityHandleStruct getChild(int);
		};

		struct TransformComponentStruct : EntityHandleStruct {
			glm::vec3 getPosition();
			glm::vec3 getScale();
			glm::vec3 getRotation();

			void setPosition(glm::vec3);
			void setScale(glm::vec3);
			void setRotation(glm::vec3);
		};

		struct MeshComponentStruct : EntityHandleStruct {
			bool isActive();
			void setActive(bool);

			bool hasMesh();
			void clear();

			Resource<GPUMesh> getMesh();
			void setMesh(Resource<GPUMesh>);

			bool assertMeshComponent(const char* funcName);
		};

		struct ShaderComponentStruct : EntityHandleStruct {
			bool hasShader();
			void clear();

			Resource<Shader> getShader();
			void setShader(Resource<Shader>);

			Resource<Texture> getTexture();
			void setTexture(Resource<Texture>);

			bool assertShaderComponent(const char* funcName);
		};

		struct CameraComponentStruct : EntityHandleStruct {
			float getFov();
			float getAspectRation();
			float getNearZ();
			float getFarZ();

			void setFov(float);
			void setAspectRation(float);
			void setNearZ(float);
			void setFarZ(float);

			bool assertCameraComponent(const char* funcName);
		};

		EntityHandleStruct getRoot();
		void constructEntityStruct(int id, void* memory);
		void copyEntityStruct(int id, void* memory);
	} // namespace StudioAPI
} // namespace Deer