/**
 * @file ContentLoader.cpp
 * @brief 关卡内容反序列化与实体创建流程实现。
 * @details
 * 主要流程为：读取二进制关卡文件 -> 解析组件块 -> 创建实体并绑定脚本/变换。
 * 同时提供运行期清理逻辑，确保测试场景退出时能回收创建的实体与资源。
 * 本实现仅在非 SHIPPING 且 Win64 条件下启用。
 */
#include "ContentLoader.h"
#include "..\Components\Script.h"

#include "..\EngineAPI\GameEntity.h"
#include "..\EngineAPI\TransformComponent.h"
#include "..\EngineAPI\ScriptComponent.h"
#include "..\Components\Entity.h"
#include "Graphics\Renderer.h"

#include <fstream>
#include <filesystem>
#include <Windows.h>

#if !defined(SHIPPING) && defined(_WIN64)

namespace XEngine::content {
namespace {

/**
 * @brief 关卡文件中的组件类型标签。
 */
enum component_type
{
	transform,
	script,

	count
};

/**
 * @brief 已创建的实体缓存，用于卸载阶段统一回收。
 */
utl::vector<game_entity::entity> entities;
/**
 * @brief 解析变换组件时复用的临时结构。
 */
transform::init_info transform_info{};
/**
 * @brief 解析脚本组件时复用的临时结构。
 */
script::init_info script_info{};


/**
 * @brief 从二进制流读取变换组件数据。
 * @param data 当前读取游标，函数返回后移动到组件末尾。
 * @param info 目标实体初始化信息。
 * @return 读取成功返回 true。
 */
bool
read_transform(const u8*& data, game_entity::entity_info& info)
{
	using namespace DirectX;
	f32 rotation[3];

	assert(!info.transform);
	memcpy(&transform_info.position[0], data, sizeof(transform_info.position)); data += sizeof(transform_info.position);
	memcpy(&rotation[0], data, sizeof(rotation)); data += sizeof(rotation);
	memcpy(&transform_info.scale[0], data, sizeof(transform_info.scale)); data += sizeof(transform_info.scale);


	XMFLOAT3A rot{ &rotation[0] };
	XMVECTOR quat{ XMQuaternionRotationRollPitchYawFromVector(XMLoadFloat3A(&rot)) };
	XMFLOAT4A rot_quat{};
	XMStoreFloat4A(&rot_quat, quat);
	memcpy(&transform_info.rotation[0], &rot_quat.x, sizeof(transform_info.rotation));

	info.transform = &transform_info;
	return true;
}


/**
 * @brief 从二进制流读取脚本组件并查找脚本工厂。
 * @param data 当前读取游标，函数返回后移动到组件末尾。
 * @param info 目标实体初始化信息。
 * @return 解析并找到脚本工厂返回 true。
 */
bool
read_script(const u8*& data, game_entity::entity_info& info)
{
	assert(!info.script);
	const u32 name_length{ *data }; data += sizeof(u32);
	if (!name_length) return false;

	assert(name_length < 256);
	char script_name[256];
	memcpy(&script_name, data, name_length); data += name_length;
	script_name[name_length] = 0;
	script_info.script_creator = script::detail::get_script_creator(script::detail::string_hash()(script_name));
	info.script = &script_info;
	return script_info.script_creator != nullptr;
}

using compoent_reader = bool(*)(const u8*&, game_entity::entity_info&);
compoent_reader component_readers[]
{
	read_transform,
	read_script,
};

static_assert(_countof(component_readers) == component_type::count);

/**
 * @brief 读取完整二进制文件到内存缓冲区。
 * @param path 文件路径。
 * @param data 输出缓冲区。
 * @param size 输出字节数。
 * @return 成功返回 true。
 */
bool
read_file(std::filesystem::path path, std::unique_ptr<u8[]>&data, u64& size)
{
	if (!std::filesystem::exists(path)) return false;

	size = std::filesystem::file_size(path);
	assert(size);
	if (!size) return false;
	data = std::make_unique<u8[]>(size);
	std::ifstream file{ path, std::ios::in | std::ios::binary };
	if (!file || !file.read((char*)data.get(), size))
	{
		file.close();
		return false;
	}

	file.close();
	return true;
}

} // namespace 


/**
 * @brief 加载 game.bin 并批量创建实体。
 * @return 全部实体创建成功返回 true。
 */
bool
load_games()
{



	std::unique_ptr<u8[]> game_data{};
	u64 size{ 0 };
	if (!read_file("game.bin", game_data, size)) return false;
	assert(game_data.get());
	const u8* at{ game_data.get() };
	constexpr u32 su32{ sizeof(u32) };
	const u32 num_entities{ *at }; at += su32;
	if (!num_entities) return false;

	for (u32 entity_index{ 0 }; entity_index < num_entities; ++entity_index)
	{
		game_entity::entity_info info{};

		const u32 entity_type{ *at }; at += su32;
		const u32 num_components{ *at }; at += su32;
		if (!num_components)return false;

		for (u32 component_index{ 0 }; component_index < num_components; ++component_index)
		{
			const u32 component_type{ *at }; at += su32;
			assert(component_type < component_type::count);
			if (!component_readers[component_type](at, info)) return false;
		}

		assert(info.transform);
		game_entity::entity entity{ game_entity::create(info) };
		if (!entity.is_valid()) return false;
		entities.emplace_back(entity);
	}

	assert(at == game_data.get() + size);
	return true;
}


/**
 * @brief 回收 load_games 创建的实体对象。
 */
void 
unload_game()
{
	for (auto entity : entities)
	{
		game_entity::remove(entity.get_id());
	}
}





/**
 * @brief 加载引擎内置着色器二进制文件。
 * @param shaders 输出字节缓冲区。
 * @param size 输出字节大小。
 * @return 加载成功返回 true。
 */
//bool 
//load_engine_shaders(std::unique_ptr<u8[]>&shaders, u64& size)
//{
//	auto path = graphics::get_engine_shaders_path();
//	return read_file(path, shaders, size);
//}

}
#endif //!defined(SHIPPING)
