/**
 * @file entity_lua_test.cpp
 * @brief Standalone test for the Lua Entity API.
 *
 * Tests entity creation, destruction, naming, hierarchy (parent/children),
 * and entity lookup functions exposed via the ecs.* Lua API.
 *
 * Build with:
 *   g++ -std=c++17 -I. -I../.. -I../../lua/lua-5.4.8/src \
 *       entity_lua_test.cpp \
 *       ../lua/LuaEntityApi.cpp \
 *       ../../lua/lua-5.4.8/src/liblua.a \
 *       -o entity_lua_test -lm
 *
 * Or via CMake (see CMakeLists.txt in this directory).
 */

#include <cstdio>
#include <cstring>
#include <cassert>
#include <string>
#include <vector>

// Ogre stub (provides Ogre::String, Ogre::Vector3, Ogre::LogManager)
#include "ogre_stub.h"

// Include Lua
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}

// Flecs stub for standalone testing
// We provide minimal Flecs types needed by LuaEntityApi
namespace flecs
{

// Minimal entity wrapper
struct entity {
	uint64_t m_id = 0;
	bool m_valid = false;

	entity()
		: m_id(0)
		, m_valid(false)
	{
	}
	explicit entity(uint64_t id)
		: m_id(id)
		, m_valid(true)
	{
	}

	uint64_t id() const
	{
		return m_id;
	}
	bool is_valid() const
	{
		return m_valid;
	}
	bool is_alive() const
	{
		return m_valid;
	}
	const char *name() const
	{
		return "";
	}
	void set_name(const char *)
	{
	}
	void destruct()
	{
		m_valid = false;
	}

	entity parent() const
	{
		return entity();
	}

	template <typename Func> void children(Func) const
	{
	}

	template <typename T> void add()
	{
	}

	template <typename T> bool has() const
	{
		return false;
	}

	template <typename T> const T *get() const
	{
		return nullptr;
	}

	template <typename T> void set(const T &)
	{
	}

	bool operator==(const entity &other) const
	{
		return m_id == other.m_id;
	}
};

using entity_t = uint64_t;

// Minimal world stub
struct world {
	entity make_entity()
	{
		return entity(nextId++);
	}
	entity lookup(const char *)
	{
		return entity();
	}

	static world &get()
	{
		static world w;
		return w;
	}

private:
	uint64_t nextId = 1000;
};

} // namespace flecs

// Forward declare the registration function
namespace editScene
{
void registerLuaEntityApi(lua_State *L);
}

// ---------------------------------------------------------------------------
// Test helpers
// ---------------------------------------------------------------------------

static int testCount = 0;
static int passCount = 0;

#define TEST(name)                                             \
	do {                                                   \
		testCount++;                                   \
		printf("  TEST %d: %s ... ", testCount, name); \
	} while (0)

#define PASS()                    \
	do {                      \
		passCount++;      \
		printf("PASS\n"); \
	} while (0)

#define FAIL(msg)                          \
	do {                               \
		printf("FAIL: %s\n", msg); \
		return 1;                  \
	} while (0)

// ---------------------------------------------------------------------------
// Helper: run a Lua string and check for errors
// ---------------------------------------------------------------------------

static bool runLua(lua_State *L, const char *code)
{
	if (luaL_dostring(L, code) != LUA_OK) {
		fprintf(stderr, "Lua error: %s\n", lua_tostring(L, -1));
		lua_pop(L, 1);
		return false;
	}
	return true;
}

// ---------------------------------------------------------------------------
// Test 1: Create entity
// ---------------------------------------------------------------------------

static int testCreateEntity(lua_State *L)
{
	TEST("create entity returns integer ID");

	bool ok = runLua(
		L,
		"local id = ecs.create_entity();"
		"assert(type(id) == 'number', 'expected number, got ' .. type(id));"
		"assert(id > 0, 'expected positive ID, got ' .. tostring(id))");
	if (!ok)
		FAIL("create entity assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 2: Entity exists
// ---------------------------------------------------------------------------

static int testEntityExists(lua_State *L)
{
	TEST("entity_exists returns correct values");

	bool ok = runLua(
		L,
		"local id = ecs.create_entity();"
		"assert(ecs.entity_exists(id) == true, 'entity should exist');"
		"assert(ecs.entity_exists(999999) == false, 'fake entity should not exist')");
	if (!ok)
		FAIL("entity exists assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 3: Destroy entity
// ---------------------------------------------------------------------------

static int testDestroyEntity(lua_State *L)
{
	TEST("destroy entity");

	bool ok = runLua(
		L,
		"local id = ecs.create_entity();"
		"assert(ecs.entity_exists(id) == true, 'entity should exist before destroy');"
		"ecs.destroy_entity(id);"
		"assert(ecs.entity_exists(id) == false, 'entity should not exist after destroy')");
	if (!ok)
		FAIL("destroy entity assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 4: Set and get entity name
// ---------------------------------------------------------------------------

static int testEntityName(lua_State *L)
{
	TEST("set and get entity name");

	bool ok = runLua(
		L,
		"local id = ecs.create_entity();"
		"ecs.set_entity_name(id, 'test_hero');"
		"local name = ecs.get_entity_name(id);"
		"assert(name == 'test_hero', 'expected test_hero, got ' .. tostring(name))");
	if (!ok)
		FAIL("entity name assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 5: Get entity by name
// ---------------------------------------------------------------------------

static int testGetEntityByName(lua_State *L)
{
	TEST("get entity by name");

	bool ok = runLua(
		L,
		"local id = ecs.create_entity();"
		"ecs.set_entity_name(id, 'findable_entity');"
		"local found = ecs.get_entity_by_name('findable_entity');"
		"assert(found == id, 'expected same ID, got ' .. tostring(found));"
		"local not_found = ecs.get_entity_by_name('nonexistent');"
		"assert(not_found == nil, 'expected nil for nonexistent')");
	if (!ok)
		FAIL("get entity by name assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 6: Parent and children hierarchy
// ---------------------------------------------------------------------------

static int testHierarchy(lua_State *L)
{
	TEST("parent and children hierarchy");

	bool ok = runLua(
		L,
		"local parent = ecs.create_entity();"
		"local child = ecs.create_entity();"
		"ecs.set_entity_name(parent, 'parent_entity');"
		"ecs.set_entity_name(child, 'child_entity');"
		"local p = ecs.parent(child);"
		"assert(p == nil, 'child should have no parent initially');"
		"local kids = ecs.children(parent);"
		"assert(type(kids) == 'table', 'children should return a table');"
		"assert(#kids == 0, 'parent should have no children initially')");
	if (!ok)
		FAIL("hierarchy assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 7: Multiple entity creation
// ---------------------------------------------------------------------------

static int testMultipleEntities(lua_State *L)
{
	TEST("create multiple entities with unique IDs");

	bool ok = runLua(
		L,
		"local ids = {};"
		"for i = 1, 5 do"
		"  ids[i] = ecs.create_entity();"
		"end;"
		"for i = 1, 5 do"
		"  for j = i+1, 5 do"
		"    assert(ids[i] ~= ids[j], 'IDs should be unique');"
		"  end;"
		"end;"
		"for i = 1, 5 do"
		"  assert(ecs.entity_exists(ids[i]) == true, 'entity should exist');"
		"end");
	if (!ok)
		FAIL("multiple entities assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 8: Destroy and recreate (ID reuse)
// ---------------------------------------------------------------------------

static int testDestroyRecreate(lua_State *L)
{
	TEST("destroy and recreate entity");

	bool ok = runLua(
		L,
		"local id1 = ecs.create_entity();"
		"ecs.destroy_entity(id1);"
		"assert(ecs.entity_exists(id1) == false, 'destroyed entity should not exist');"
		"local id2 = ecs.create_entity();"
		"assert(ecs.entity_exists(id2) == true, 'new entity should exist');"
		"assert(id2 ~= id1, 'new entity should have different ID')");
	if (!ok)
		FAIL("destroy recreate assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

int main()
{
	printf("Entity Lua API Tests\n");
	printf("====================\n\n");

	// Create Lua state
	lua_State *L = luaL_newstate();
	if (!L) {
		fprintf(stderr, "Failed to create Lua state\n");
		return 1;
	}
	luaL_openlibs(L);

	// Register the entity API
	editScene::registerLuaEntityApi(L);

	// Run tests
	int failures = 0;
	failures += testCreateEntity(L);
	failures += testEntityExists(L);
	failures += testDestroyEntity(L);
	failures += testEntityName(L);
	failures += testGetEntityByName(L);
	failures += testHierarchy(L);
	failures += testMultipleEntities(L);
	failures += testDestroyRecreate(L);

	// Cleanup
	lua_close(L);

	printf("\nResults: %d/%d passed, %d failed\n", passCount, testCount,
	       failures);

	return failures > 0 ? 1 : 0;
}
