#include "Deer/Components.h"
#include "Deer/Enviroment.h"

namespace Deer {
	Entity::Entity(entt::entity handle, Environment* scene, uint16_t entityID)
	    : m_entityHandle(handle),
	      m_environment(scene),
	      m_entityID(entityID),
	      m_exists(true) {}

	void Entity::setParent(Entity& parent) {
		DEER_CORE_ASSERT(isValid(), "Entity is not valid");
		DEER_CORE_ASSERT(parent.m_environment == m_environment,
		                 "Can not set parent from diferent environments");
		DEER_CORE_ASSERT(parent.isValid(), "Parent is not valid");
		if (parent.getId() == getId()) return;

		Entity& current_parent = getParent();
		if (parent.isDescendantOf(*this)) {
			return;
		}

		if (!parent.getComponent<RelationshipComponent>().addChildrenId(
		        getId())) {
			DEER_CORE_ERROR(
			    "Max child count!!!, could not set parent {0} to entity {1}",
			    parent.getComponent<TagComponent>().tag.c_str(),
			    getComponent<TagComponent>().tag.c_str());
			return;
		}

		m_parentID = parent.getId();
		current_parent.getComponent<RelationshipComponent>().removeChildren(
		    getId());

		getComponent<RelationshipComponent>().parent_id = parent.getId();
	}

	bool Entity::isDescendantOf(Entity& parent) const {
		DEER_CORE_ASSERT(isValid(), "Entity is not valid");
		if (getId() == parent.getId()) return true;
		if (isRoot()) return false;

		return getParent().isDescendantOf(parent);
	}

	Entity& Entity::duplicate() {
		DEER_CORE_ASSERT(isValid(), "Entity is not valid");
		Entity& creation = m_environment->createEntity(
		    getComponent<TagComponent>().tag + "(d)");

		creation.setParent(getParent());

		creation.getComponent<TransformComponent>() =
		    getComponent<TransformComponent>();

#ifdef DEER_RENDER
		if (m_environment->m_registry.any_of<MeshComponent>(
		        m_entityHandle))
			creation.addComponent<MeshComponent>(
			    getComponent<MeshComponent>());

		if (m_environment->m_registry.any_of<CameraComponent>(m_entityHandle))
			creation.addComponent<CameraComponent>(
			    getComponent<CameraComponent>());
#endif
		return creation;
	}

	void Entity::destroy() {
		DEER_CORE_ASSERT(isValid(), "Entity is not valid");
		DEER_CORE_ASSERT(!isRoot(), "Can not destroy the root");
		m_environment->destroyEntity(getId());
	}

	Entity& Entity::getParent() const {
		DEER_CORE_ASSERT(isValid(), "Entity is not valid");
		return m_environment->getEntity(m_parentID);
	}

	glm::mat4 Entity::getWorldMatrix() {
		if (isRoot()) return glm::mat4(1.0f);

		return getParent().getWorldMatrix() * getRelativeMatrix();
	}

	glm::mat4 Entity::getRelativeMatrix() {
		return getComponent<TransformComponent>().getMatrix();
	}
}  // namespace Deer
