#include <Entities/EntityMemoryPool.h>
#include <Entities/EntityView.h>
#include <log.h>
#include <Entities/EntityManager.h>
#include <Entities/Entity.h>

#include <utility.h>

inline constexpr index_t PLAYER_INDEX = util::tagStart[Tag::player];

int EntityManager::update()
{
	//adding entities
	for(int i = 0; i < util::TAG_COUNT; i++)
	{
		#ifdef CORE_DEBUG
		if (m_numEntities[i] + m_numEntitiesToAdd[i] >= util::getTagSize(i))
		{
			LOG("Error: Entity Overflow");
			return ErrorCode::entityOverflow;
		}
		#endif

		EntityView toAdd(m_entityData, util::getTagStart(i) + m_numEntities[i], m_numEntitiesToAdd[i] - 1);

		for (auto ent : toAdd)
		{
			ent.add();
			m_entityData.m_ids[ent.m_index] = m_nextId++;
			m_numEntities[i]++;

			#ifdef CORE_DEBUG
			m_totalEntities++;
			#endif
		}

		m_numEntitiesToAdd[i] = 0;

		//removing entites
		EntityView entites(m_entityData, util::getTagStart(i), m_numEntities[i]);
		Entity swapWith(m_entityData, 0);

		for (auto ent : entites)
		{
			if (ent.alive()) continue;

			if (ent.m_index != m_numEntities[i] - 1)//not at the end
			{
				swapWith.m_index = m_numEntities[i] - 1;
				std::apply([=](auto&&... args) {((args.swap(ent.m_index, swapWith.m_index)), ...); }, m_entityData.m_components);

				m_numEntities[i]--;
				continue;
			}
			
			m_numEntities[i]--;
		}
	}


	return 0;
}

inline Entity EntityManager::player()
{
	return Entity(m_entityData, PLAYER_INDEX);
}

EntityView EntityManager::getEntities(tag_t tag)
{
	return EntityView(m_entityData, util::getTagStart(tag), m_numEntities[tag]);
}

Entity EntityManager::addEntity(tag_t tag)
{	
	#ifdef CORE_DEBUG
	m_totalEntities++;
	#endif

	return Entity(m_entityData, util::tagStart[tag] + m_numEntities[tag] + m_numEntitiesToAdd[tag]++);
}