/**
 * @file PlatformWin32.cpp
 * @brief Win32 平台窗口系统实现。
 * @details
 * 该文件实现平台窗口后端的完整行为，包括：
 * - Win32 窗口类注册与窗口创建；
 * - 窗口 ID 与 HWND 的双向关联管理；
 * - 大小变化、销毁、全屏切换等消息处理；
 * - 对 Platform.h / Window.h 暴露接口的底层支撑。
 */
#ifdef _WIN64
#include "Platform.h"
#include "PlatformTypes.h"

namespace XEngine::platform {



namespace {
/**
 * @brief Win32 窗口实例运行时状态。
 */
struct window_info
{
	HWND		hwnd{ nullptr };
	RECT		client_area{ 0,0,1920,1080 };
	RECT		fullscreen_area{};
	POINT		top_left{ 0,0 };
	DWORD		style{ WS_VISIBLE };
	bool		is_fullscreen{ false };
	bool		is_closed{ false };

};

/**
 * @brief 窗口对象存储池。
 */
utl::free_list<window_info> windows;




/**
 * @brief 根据窗口 ID 获取窗口状态对象。
 * @param id 窗口 ID。
 * @return 对应窗口状态引用。
 */
window_info&
get_from_id(window_id id)
{
	assert(windows[id].hwnd);
	return windows[id];
}

/**
 * @brief 根据 HWND 获取窗口状态对象。
 * @param handle 原生窗口句柄。
 * @return 对应窗口状态引用。
 */
window_info&
get_from_handle(window_handle handle)
{
	const window_id id{ (id::id_type)GetWindowLongPtr(handle, GWLP_USERDATA) };
	return get_from_id(id);
}

/**
 * @brief 标记窗口是否发生了可见尺寸变更。
 */
bool resized{ false };

/**
 * @brief 按目标客户区更新窗口尺寸与位置。
 * @param info 窗口状态。
 * @param area 目标客户区矩形。
 */
void
resize_window(const window_info& info, const RECT& area)
{
	RECT window_rect{ area };
	AdjustWindowRect(&window_rect, info.style, FALSE);

	const s32 width{ window_rect.right - window_rect.left };
	const s32 height{ window_rect.bottom - window_rect.top };

	MoveWindow(info.hwnd, info.top_left.x, info.top_left.y, width, height, true);
}

/// <Window parameter implementation>


/**
 * @brief 查询窗口是否处于全屏状态。
 * @param id 窗口 ID。
 * @return 全屏返回 true。
 */
bool
is_window_fullscreen(window_id id)
{
	assert(id != u32_invalid_id);
	return get_from_id(id).is_fullscreen;
}

/**
 * @brief 查询窗口原生句柄。
 * @param id 窗口 ID。
 * @return HWND 句柄。
 */
window_handle
get_window_handle(window_id id)
{
	return get_from_id(id).hwnd;
}

/**
 * @brief 设置窗口标题文本。
 * @param id 窗口 ID。
 * @param caption 标题文本。
 */
void
set_window_caption(window_id id, const wchar_t* caption)
{
	window_info& info{ get_from_id(id) };
	SetWindowText(info.hwnd, caption);
}

/**
 * @brief 查询窗口矩形（客户区或全屏区）。
 * @param id 窗口 ID。
 * @return 左上右下坐标向量。
 */
math::u32v4
get_window_size(window_id id)
{
	window_info& info{ get_from_id(id) };
	RECT& rect{ info.is_fullscreen ? info.fullscreen_area : info.client_area };
	return { (u32)rect.left,(u32)rect.top,(u32)rect.right,(u32)rect.bottom };
}

/**
 * @brief 调整窗口客户区尺寸。
 * @param id 窗口 ID。
 * @param width 新宽度。
 * @param height 新高度。
 */
void
resize_window(window_id id, u32 width, u32 height)
{
	window_info& info{ get_from_id(id) };
	// when we host the window in the level editor we just update 
	// the internal data.
	if (info.style & WS_CHILD)
	{
		GetClientRect(info.hwnd, &info.client_area);
	}
	else
	{

		RECT& area{ info.is_fullscreen ? info.fullscreen_area : info.client_area };
		area.bottom = area.top + height;
		area.right = area.left + width;

		resize_window(info, area);
	}

}

/**
 * @brief 查询窗口是否已被关闭。
 * @param id 窗口 ID。
 * @return 已关闭返回 true。
 */
bool
is_window_close(window_id id)
{
	return get_from_id(id).is_closed;
}

/// <Window parameter implementation>

/**
 * @brief 平台内部默认窗口过程。
 * @param hwnd 窗口句柄。
 * @param msg 消息类型。
 * @param wparam 消息参数。
 * @param lparam 消息参数。
 * @return 消息处理结果。
 */
LRESULT CALLBACK internal_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{

	switch (msg)
	{
	case WM_NCCREATE:
	{

		DEBUG_OP(SetLastError(0));
		const window_id id{ windows.add() };
		windows[id].hwnd = hwnd;
		SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)id);
		assert(GetLastError() == 0);
	}
	break;
	case WM_DESTROY:
	
		get_from_handle(hwnd).is_closed = true;
	
		break;

	case WM_SIZE:
		resized = (wparam != SIZE_MINIMIZED);

		break;

	default:
		break;
	}

	if (resized && GetAsyncKeyState(VK_LBUTTON) >= 0)
	{
		window_info& info{ get_from_handle(hwnd) };
		assert(info.hwnd);
		GetClientRect(info.hwnd, info.is_fullscreen ? &info.fullscreen_area : &info.client_area);
		resized = false;
	}

	LONG_PTR long_ptr{ GetWindowLongPtr(hwnd, 0) };
	return long_ptr
		? ((window_proc)long_ptr)(hwnd, msg, wparam, lparam)
		: DefWindowProc(hwnd, msg, wparam, lparam);

	assert(GetLastError() == 0);
}

/**
 * @brief 切换窗口全屏状态。
 * @param id 窗口 ID。
 * @param is_fullscreen 目标全屏状态。
 */
void
set_window_fullscreen(window_id id, bool is_fullscreen)
{
	window_info& info{ windows[id] };
	if (info.is_fullscreen != is_fullscreen)
	{
		info.is_fullscreen = is_fullscreen;

		if (is_fullscreen)
		{
			GetClientRect(info.hwnd, &info.client_area);
			RECT rect;
			GetWindowRect(info.hwnd, &rect);
			info.top_left.x = rect.left;
			info.top_left.y = rect.top;
			SetWindowLongPtr(info.hwnd, GWL_STYLE, info.style);
			ShowWindow(info.hwnd, SW_MAXIMIZE);
		}
		else
		{
			SetWindowLongPtr(info.hwnd, GWL_STYLE, info.style);
			resize_window(info, info.client_area);
			ShowWindow(info.hwnd, SW_SHOWNORMAL);
		}
	}
}

} // namespace

/**
 * @brief 创建 Win32 窗口并注册到窗口池。
 * @param init_info 可选窗口初始化参数。
 * @return 创建成功的窗口句柄对象。
 */
window
create_window(const window_init_info* init_info /* = nullptr */)
{
	window_proc callback{ init_info ? init_info->callback : nullptr };	// 回调窗口过程：由初始化参数提供；未提供时为 nullptr。
	window_handle parent{ init_info ? init_info->parent : nullptr };		// 父窗口句柄：用于子窗口挂载；未提供时创建顶层窗口。


	WNDCLASSEX wc;
	ZeroMemory(&wc, sizeof(WNDCLASSEX));

	// 初始化 WNDCLASSEX 字段。
	wc.cbSize = sizeof(WNDCLASSEX);										// 结构体大小。
	wc.style = CS_HREDRAW | CS_VREDRAW;									// 水平/垂直尺寸变化时重绘。
	wc.lpfnWndProc = internal_window_proc;								// 默认窗口过程入口。
	wc.cbClsExtra = 0;													// 类额外字节数。
	wc.cbWndExtra = callback ? sizeof(callback) : 0;					// 实例额外字节数：有回调时用于存储回调指针。
	wc.hInstance = 0;													// 当前模块实例句柄（使用默认）。
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);							// 大图标。
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);							// 光标。
	wc.hbrBackground = CreateSolidBrush(RGB(26, 48, 76));				// 背景画刷。
	wc.lpszMenuName = NULL;												// 菜单名（无）。
	wc.lpszClassName = L"XWindow";										// 窗口类名。
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);						// 小图标。


	// 注册窗口类。
	if (!RegisterClassEx(&wc))
	{
		// 若类已注册或注册失败，后续创建窗口时由系统返回结果。
	}

	window_info info{};
	info.client_area.right = (init_info && init_info->width) ? info.client_area.left + init_info->width : info.client_area.right;
	info.client_area.bottom = (init_info && init_info->height) ? info.client_area.top + init_info->height : info.client_area.bottom;
	info.style |= parent ? WS_CHILD : WS_OVERLAPPEDWINDOW;

	RECT rect{ info.client_area };
	AdjustWindowRect(&rect, info.style, FALSE);

	const wchar_t* caption{ (init_info && init_info->caption) ? init_info->caption : L"XGame" };
	const s32 left{ (init_info) ? init_info->left : info.top_left.x };
	const s32 top{ (init_info) ? init_info->top : info.top_left.y };

	const s32 width{ rect.right - rect.left };
	const s32 height{ rect.bottom - rect.top };


	// 创建窗口实例。

	info.hwnd = CreateWindowEx(
		0,							// 扩展样式。
		wc.lpszClassName,			// 窗口类名。
		caption,					// 窗口标题。
		info.style,					// 窗口样式。

		// 尺寸与位置。
		left, top, width, height,

		parent,						// 父窗口句柄（nullptr 表示顶层窗口）。
		nullptr,					// 菜单句柄（未使用）。
		nullptr,					// 实例句柄（未显式传入）。
		nullptr						// 创建参数（未使用）。
	);

	if (info.hwnd)
	{
		DEBUG_OP(SetLastError(0));

		if (callback) SetWindowLongPtr(info.hwnd, 0, (LONG_PTR)callback);
		assert(GetLastError() == 0);

		ShowWindow(info.hwnd, SW_SHOWNORMAL);
		UpdateWindow(info.hwnd);

		window_id id{ (id::id_type)GetWindowLongPtr(info.hwnd, GWLP_USERDATA) };
		windows[id] = info;
		return window{ id };
	}

	return {}; // 创建失败时返回无效窗口句柄。
}

/**
 * @brief 销毁窗口并从窗口池移除。
 * @param id 窗口 ID。
 */
void
remove_window(window_id id)
{
	window_info& info{ get_from_id(id) };
	DestroyWindow(info.hwnd);
	windows.remove(id);
}
}

#include "IncludeWindowCpp.h"


#endif // _WIN64
