/**
 * @file game_mode_lua_test.cpp
 * @brief Standalone test for the Lua Game Mode API.
 *
 * Tests the ecs.is_editor_mode(), ecs.is_game_mode(), ecs.is_game_playing(),
 * ecs.is_game_menu(), ecs.is_game_paused(), ecs.get_game_mode(), and
 * ecs.get_game_play_state() functions exposed via the ecs.* Lua API.
 *
 * Build with:
 *   g++ -std=c++17 -I. -I../.. -I../../lua/lua-5.4.8/src \
 *       game_mode_lua_test.cpp \
 *       ../lua/LuaGameModeApi.cpp \
 *       ../../lua/lua-5.4.8/src/liblua.a \
 *       -o game_mode_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>
}

// Forward declare the registration function
namespace editScene
{
void registerLuaGameModeApi(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: Default state is editor mode
// ---------------------------------------------------------------------------

static int testDefaultIsEditor(lua_State *L)
{
	TEST("default state is editor mode");

	bool ok = runLua(L, "assert(ecs.is_editor_mode() == true, "
			    "'expected editor mode by default');"
			    "assert(ecs.is_game_mode() == false, "
			    "'expected not game mode by default');"
			    "local mode = ecs.get_game_mode();"
			    "assert(mode == 'editor', "
			    "'expected editor, got ' .. tostring(mode))");
	if (!ok)
		FAIL("default state assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 2: Default gameplay state is menu
// ---------------------------------------------------------------------------

static int testDefaultPlayState(lua_State *L)
{
	TEST("default gameplay state is menu");

	bool ok = runLua(
		L, "assert(ecs.is_game_playing() == false, "
		   "'expected not playing by default');"
		   "assert(ecs.is_game_menu() == false, "
		   "'expected not game menu by default (we are in editor)');"
		   "assert(ecs.is_game_paused() == false, "
		   "'expected not paused by default');"
		   "local state = ecs.get_game_play_state();"
		   "assert(state == 'menu', "
		   "'expected menu, got ' .. tostring(state))");
	if (!ok)
		FAIL("default play state assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 3: Return types are correct
// ---------------------------------------------------------------------------

static int testReturnTypes(lua_State *L)
{
	TEST("return types are correct");

	bool ok = runLua(L,
			 "assert(type(ecs.is_editor_mode()) == 'boolean', "
			 "'is_editor_mode should return boolean');"
			 "assert(type(ecs.is_game_mode()) == 'boolean', "
			 "'is_game_mode should return boolean');"
			 "assert(type(ecs.is_game_playing()) == 'boolean', "
			 "'is_game_playing should return boolean');"
			 "assert(type(ecs.is_game_menu()) == 'boolean', "
			 "'is_game_menu should return boolean');"
			 "assert(type(ecs.is_game_paused()) == 'boolean', "
			 "'is_game_paused should return boolean');"
			 "assert(type(ecs.get_game_mode()) == 'string', "
			 "'get_game_mode should return string');"
			 "assert(type(ecs.get_game_play_state()) == 'string', "
			 "'get_game_play_state should return string')");
	if (!ok)
		FAIL("return types assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 4: Predicates are mutually exclusive
// ---------------------------------------------------------------------------

static int testMutualExclusion(lua_State *L)
{
	TEST("editor and game mode are mutually exclusive");

	bool ok = runLua(L,
			 "assert(ecs.is_editor_mode() ~= ecs.is_game_mode(), "
			 "'editor and game should be mutually exclusive')");
	if (!ok)
		FAIL("mutual exclusion assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 5: Game play state predicates are false in editor mode
// ---------------------------------------------------------------------------

static int testPlayStateInEditor(lua_State *L)
{
	TEST("game play state predicates are false in editor mode");

	bool ok = runLua(L, "assert(ecs.is_game_playing() == false, "
			    "'is_game_playing should be false in editor');"
			    "assert(ecs.is_game_menu() == false, "
			    "'is_game_menu should be false in editor');"
			    "assert(ecs.is_game_paused() == false, "
			    "'is_game_paused should be false in editor')");
	if (!ok)
		FAIL("play state in editor assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 6: get_game_mode returns valid string
// ---------------------------------------------------------------------------

static int testGetGameModeString(lua_State *L)
{
	TEST("get_game_mode returns valid string");

	bool ok = runLua(L,
			 "local mode = ecs.get_game_mode();"
			 "assert(mode == 'editor' or mode == 'game', "
			 "'expected editor or game, got ' .. tostring(mode))");
	if (!ok)
		FAIL("get_game_mode string assertion failed");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 7: get_game_play_state returns valid string
// ---------------------------------------------------------------------------

static int testGetPlayStateString(lua_State *L)
{
	TEST("get_game_play_state returns valid string");

	bool ok = runLua(
		L,
		"local state = ecs.get_game_play_state();"
		"assert(state == 'menu' or state == 'playing' or state == 'paused', "
		"'expected menu/playing/paused, got ' .. tostring(state))");
	if (!ok)
		FAIL("get_game_play_state string assertion failed");

	PASS();
	return 0;
}

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

int main()
{
	printf("Game Mode 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 game mode API
	editScene::registerLuaGameModeApi(L);

	// Run tests
	int failures = 0;
	failures += testDefaultIsEditor(L);
	failures += testDefaultPlayState(L);
	failures += testReturnTypes(L);
	failures += testMutualExclusion(L);
	failures += testPlayStateInEditor(L);
	failures += testGetGameModeString(L);
	failures += testGetPlayStateString(L);

	// Cleanup
	lua_close(L);

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

	return failures > 0 ? 1 : 0;
}
