#include <psemek/test/test.hpp>

#include <psemek/ecs/container.hpp>
#include <psemek/random/generator.hpp>
#include <psemek/random/uniform.hpp>

using namespace psemek;
using namespace psemek::ecs;

namespace
{

	struct component_1
	{
		int value;

		static constexpr util::uuid uuid()
		{
			return {1, 0};
		}
	};

	struct component_2
	{
		int value;

		static constexpr util::uuid uuid()
		{
			return {2, 0};
		}
	};

}

test_case(ecs_cache_empty)
{
	container container;

	container.create();
	container.create(component_1{10});
	container.create(component_2{20});
	container.create(component_1{100}, component_2{200});

	auto cache = container.cache();

	expect_different_ptr(cache.get(), nullptr);
	expect(cache->with_uuids.empty());
	expect_equal(cache->entries.size(), 4);
}

test_case(ecs_cache_components)
{
	container container;

	container.create();
	container.create(component_1{10});
	container.create(component_2{20});
	container.create(component_1{100}, component_2{200});

	auto cache = container.cache<component_1>();

	expect_different_ptr(cache.get(), nullptr);
	expect_equal(cache->with_uuids.size(), 1);
	expect_equal(cache->entries.size(), 2);
}

test_case(ecs_cache_update)
{
	container container;

	auto cache = container.cache<component_1>();

	expect_different_ptr(cache.get(), nullptr);
	expect_equal(cache->with_uuids.size(), 1);
	expect_equal(cache->entries.size(), 0);

	container.create();
	expect_equal(cache->with_uuids.size(), 1);
	expect_equal(cache->entries.size(), 0);

	container.create(component_1{10});
	expect_equal(cache->with_uuids.size(), 1);
	expect_equal(cache->entries.size(), 1);

	container.create(component_2{20});
	expect_equal(cache->with_uuids.size(), 1);
	expect_equal(cache->entries.size(), 1);

	container.create(component_1{100}, component_2{200});
	expect_equal(cache->with_uuids.size(), 1);
	expect_equal(cache->entries.size(), 2);
}

test_case(ecs_cache_apply)
{
	container container;

	auto cache = container.cache<component_1>();

	int call_count = 0;
	auto counter = [&](component_1 const &){ ++call_count; };

	int count_0 = 16;
	int count_1 = 32;
	int count_2 = 64;
	int count_12 = 128;

	call_count = 0;
	container.apply<component_1>(counter, cache);
	expect_equal(call_count, 0);

	for (int i = 0; i < count_0; ++i)
		container.create();
	call_count = 0;
	container.apply<component_1>(counter, cache);
	expect_equal(call_count, 0);

	for (int i = 0; i < count_1; ++i)
		container.create(component_1{10});
	call_count = 0;
	container.apply<component_1>(counter, cache);
	expect_equal(call_count, count_1);

	for (int i = 0; i < count_2; ++i)
		container.create(component_2{20});
	call_count = 0;
	container.apply<component_1>(counter, cache);
	expect_equal(call_count, count_1);

	for (int i = 0; i < count_12; ++i)
		container.create(component_1{100}, component_2{200});
	call_count = 0;
	container.apply<component_1>(counter, cache);
	expect_equal(call_count, count_1 + count_12);
}
