#include "Deer/Enviroment.h"

#include "Deer/Application.h"
#include "Deer/Components.h"
#include "Deer/Log.h"
#include "DeerRender/Render/Render.h"
#include "DeerRender/Render/RenderUtils.h"
#include "DeerRender/Render/Texture.h"

namespace Deer {
	Environment::Environment() {
		entities = MakeScope<std::array<Entity, ENVIRONMENT_MAX_ENTITIES>>();
		clear();
	}

	Environment::~Environment() {}

	void Environment::clear() {
		// Clear all existing entities and map
		m_registry.clear();

		m_mainCamera = 0;
		m_idCreationOffset = 0;
		m_maxIdValue = 0;
		// We set it to one because we count root
		m_entityCount = 1;

		createEntityWithId(0, "root");
	}

	Entity& Environment::getEntity(uint16_t id) const {
		DEER_CORE_ASSERT(entityExists(id), "Entity id {0} does not exist", id);
		Entity& refEntity = (*entities)[id];
		return refEntity;
	}

	bool Environment::entityExists(uint16_t id) const {
		if (id < 0) return false;
		if (id > m_maxIdValue) return false;
		if (id >= ENVIRONMENT_MAX_ENTITIES) return false;
		Entity& refEntity = (*entities)[id];
		return refEntity.isValid();
	}

	Entity& Environment::createEntity(const std::string& name) {
		uint16_t id;
		do {
			id = pullEntityID();
			DEER_CORE_ASSERT(id < ENVIRONMENT_MAX_ENTITIES,
			                 "Fatal error, max number of entities exited");
		} while (entityExists(id));

		entt::entity entityID = m_registry.create();
		Entity& entity = (*entities)[id];
		entity = {entityID, this, id};

		entity.addComponent<TagComponent>(name, id);
		entity.addComponent<RelationshipComponent>();
		entity.addComponent<TransformComponent>();
		entity.m_exists = true;

		m_entityCount++;
		entity.m_parentID = 0;
		if (!getRoot().getComponent<RelationshipComponent>().addChildrenId(
		        id)) {
			DEER_CORE_ERROR("Root is full!");
		}

		return entity;
	}

	Entity& Environment::createEntityWithId(uint16_t id,
	                                        const std::string& name) {
		// We want to initialize all entities that are not initialized to a
		// default state of invalid
		for (int i = m_maxIdValue + 1; i < id; i++) {
			Entity& nullEntity = (*entities)[i];
			nullEntity.m_exists = false;
		}
		if (m_maxIdValue < id) m_maxIdValue = id;

		Entity& entity = (*entities)[id];
		entt::entity entityID = m_registry.create();
		entity = {entityID, this, id};
		entity.m_exists = true;

		entity.addComponent<TagComponent>(name, id);
		entity.addComponent<RelationshipComponent>();
		entity.addComponent<TransformComponent>();

		m_entityCount++;
		if (id != 0) {
			if (!getRoot().getComponent<RelationshipComponent>().addChildrenId(
			        id)) {
				DEER_CORE_ERROR("Root is full!");
			}
		}
		return entity;
	}

	void Environment::destroyEntity(uint16_t entityID) {
		DEER_CORE_ASSERT(entityExists(entityID), "Entity id {0} does not exist",
		                 entityID);
		DEER_CORE_ASSERT(entityID != 0, "Can not destroy root");

		Entity& entity = (*entities)[entityID];
		entity.getParent().getComponent<RelationshipComponent>().removeChildren(
		    entityID);

		RelationshipComponent& relationship =
		    entity.getComponent<RelationshipComponent>();
		// We want to delete all childrens
		for (int i = 0; i < relationship.childCount; i++) {
			uint16_t childID = relationship.getChildrenId(i);
			destroyEntity(childID);
		}

		if (m_mainCamera == entityID) m_mainCamera = 0;
		if (entityID <= m_idCreationOffset) m_idCreationOffset = entityID - 1;

		m_registry.destroy(entity.m_entityHandle);
		entity.m_exists = false;
		m_entityCount--;
	}

	uint16_t Environment::tryGetMainCamera() { return m_mainCamera; }

	void Environment::setMainCamera(Entity& entity) {
		if (!entity.isValid()) m_mainCamera = 0;

		m_mainCamera = entity.getId();
	}
}  // namespace Deer