//
// Created by Administrator on 25-3-1.
//
#include <iostream>

#include "../render_window.h"
#include <Windows.h>

#define WINDOW_HANDLE static_cast<HWND>(window_handle)

std::vector<mirage_window*> windows;

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	switch (uMsg) {
		case WM_CLOSE:
			for (const auto& window: windows) {
				if (window->get_window_handle() == hwnd) {
					window->close();
					break;
				}
			}
			std::erase_if(windows, [hwnd](const mirage_window* window) { return window->get_window_handle() == hwnd; });
			return 0;
		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
		case WM_SIZE:
			for (const auto& window: windows) {
				if (window->get_window_handle() == hwnd) {
					window->on_resize(LOWORD(lParam), HIWORD(lParam));
					break;
				}
			}
			return 0;
		default:
			return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}
}

bool mirage_window::create_window(int width, int height, const wchar_t* title) {
	WNDCLASS wc      = {};
	wc.lpfnWndProc   = WindowProc;
	wc.hInstance     = GetModuleHandle(nullptr);
	wc.lpszClassName = L"mirage_window_class";
	wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO);
	RegisterClass(&wc);

	RECT rect = { 0, 0, width, height };
	AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);

	window_handle = (void*)CreateWindowW(
		L"mirage_window_class", title,
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT,
		rect.right - rect.left, rect.bottom - rect.top,
		NULL, NULL, GetModuleHandleW(NULL), NULL
	);

	if (!window_handle) {
		std::cerr << "Failed to create window" << std::endl;
		return false;
	}

	windows.push_back(this);
	return true;
}

void mirage_window::show() { ShowWindow(WINDOW_HANDLE, SW_SHOW); }
void mirage_window::hide() { ShowWindow(WINDOW_HANDLE, SW_HIDE); }

void mirage_window::close() {
	close_request = true;
	DestroyWindow(WINDOW_HANDLE);
}

void mirage_window::maximize() { ShowWindow(WINDOW_HANDLE, SW_MAXIMIZE); }
void mirage_window::minimize() { ShowWindow(WINDOW_HANDLE, SW_MINIMIZE); }

void mirage_window::move(int x, int y) {
	RECT rect;
	GetWindowRect(WINDOW_HANDLE, &rect);
	MoveWindow(WINDOW_HANDLE, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
}

void mirage_window::resize(int width, int height) {
	RECT rect;
	GetWindowRect(WINDOW_HANDLE, &rect);
	MoveWindow(WINDOW_HANDLE, rect.left, rect.top, width, height, TRUE);
}

Eigen::Vector2i mirage_window::get_window_size() const {
	// 获取窗口大小, 包括边框和标题栏
	RECT rect;
	if (GetWindowRect(WINDOW_HANDLE, &rect)) {
		int width  = rect.right - rect.left;
		int height = rect.bottom - rect.top;
		return Eigen::Vector2i(width, height);
	}
	return Eigen::Vector2i(0, 0);
}

Eigen::Vector2i mirage_window::get_window_frame_size() const {
	// 获取窗口大小, 不包括边框和标题栏 (客户区大小)
	RECT rect;
	if (GetClientRect(WINDOW_HANDLE, &rect)) {
		int width  = rect.right - rect.left;
		int height = rect.bottom - rect.top;
		return Eigen::Vector2i(width, height);
	}
	return Eigen::Vector2i(0, 0);
}

Eigen::Vector2i mirage_window::get_window_position() const {
	RECT rect;
	if (!GetWindowRect(WINDOW_HANDLE, &rect)) { return {}; }
	return { rect.left, rect.top };
}

void* mirage_window::get_window_handle() const { return window_handle; }

mirage_window& mirage_window::set_title(const wchar_t* title) {
	SetWindowText(WINDOW_HANDLE, title);
	return *this;
}

mirage_window& mirage_window::set_has_minimize_button(bool has_minimize_button) {
	auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
	if (has_minimize_button) { style |= WS_MINIMIZEBOX; } else { style &= ~WS_MINIMIZEBOX; }
	SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
	return *this;
}

mirage_window& mirage_window::set_has_maximize_button(bool has_maximize_button) {
	auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
	if (has_maximize_button) { style |= WS_MAXIMIZEBOX; } else { style &= ~WS_MAXIMIZEBOX; }
	SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
	return *this;
}

mirage_window& mirage_window::set_has_close_button(bool has_close_button) {
	auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
	if (has_close_button) { style |= WS_SYSMENU; } else { style &= ~WS_SYSMENU; }
	SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
	return *this;
}

mirage_window& mirage_window::set_has_border(bool has_border) {
	auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
	if (has_border) { style |= WS_BORDER; } else { style &= ~WS_BORDER; }
	SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
	return *this;
}

mirage_window& mirage_window::set_has_caption(bool has_caption) {
	auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
	if (has_caption) { style |= WS_CAPTION; } else { style &= ~WS_CAPTION; }
	SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
	return *this;
}

mirage_window& mirage_window::set_has_resizable_border(bool has_resizable_border) {
	auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
	if (has_resizable_border) { style |= WS_THICKFRAME; } else { style &= ~WS_THICKFRAME; }
	SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
	return *this;
}

mirage_window& mirage_window::set_topmost(bool is_topmost) {
	auto style = GetWindowLong(WINDOW_HANDLE, GWL_EXSTYLE);
	if (is_topmost) { style |= WS_EX_TOPMOST; } else { style &= ~WS_EX_TOPMOST; }
	SetWindowLong(WINDOW_HANDLE, GWL_EXSTYLE, style);
	return *this;
}

bool mirage_window::poll_events() {
	MSG  msg;
	bool has_messages = false;
	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
		has_messages = true;
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return has_messages;
}

const std::vector<mirage_window*>& mirage_window::get_windows() { return windows; }

void mirage_window::on_resize(int width, int height) {
	state->swapchain.width  = width;
	state->swapchain.height = height;
	state->resize(Eigen::Vector2i(width, height));
}
