HINSTANCE win32_instance = {0};
PlatformWindow win32_window = {0};
b32 global_quit = false;

LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param, LPARAM l_param)
{
	LRESULT result = 0;

	switch (message)
	{
		case WM_SIZE: 
			{
				Printfln("Window resizing");
				win32_window.w = LOWORD(l_param);
				win32_window.h = HIWORD(l_param);
				SetRenderResolution(win32_window.w, win32_window.h);
			}	break;
		case WM_DESTROY: // TODO(MA): Probably handle these separately but for now, they're together
		case WM_CLOSE:
			{
				Printf("quitting");
				global_quit = true;
			} break;
		case WM_ACTIVATEAPP:
			{
				OutputDebugStringA("WM_ACTIVATEAPP\n");
			} break;
		default:
			{
				result = DefWindowProc(window, message, w_param, l_param);
			} break;
	}

	return result;
}

b32 LoadLib(const char *name, Library *out_lib)
{
	b32 success = true;

	out_lib->module = LoadLibraryA("vulkan-1.dll");
	if (!out_lib->module)
		success = false;

	return success;
}

b32 LoadFn(const char *name, Library *lib, Function *out_fn)
{
	b32 success = true;

	out_fn->fn = GetProcAddress(lib->module, name);
	if (!out_fn->fn)
		success = false;

	return success;
}

rawptr MemAlloc(isize size)
{
	return (rawptr)VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
}

rawptr MemAllocZeroed(isize size)
{
	return _MemAlloc(size);
}

isize GetPageSize()
{
	return 0;
}

i32 _Write(void const *str, DWORD std_handle)
{
	DWORD written;
	BOOL success = WriteFile(GetStdHandle(std_handle), str, StrLen(str), &written, NULL);
	return success ? (i32)written : -1;
}

i32 _Printf(const char *fmt, va_list arg)
{
	char buffer[1024];

	int sprf_res = stbsp_vsnprintf(&buffer[0], 1024, fmt, arg);

	i32 pr_res;
	if (sprf_res < 0)
		pr_res = sprf_res;
	else
		pr_res = _Write(buffer, STD_OUTPUT_HANDLE);

	return pr_res;
}

i32 _Printfln(const char *fmt, va_list arg)
{
	char buffer[1024];

	int sprf_res = stbsp_vsnprintf(&buffer[0], 1023, fmt, arg);

	i32 pr_res;
	if (sprf_res < 0)
		pr_res = sprf_res;
	else
	{
		buffer[sprf_res] = '\n';
		buffer[sprf_res+1] = '\0';
		pr_res = _Write(&buffer, STD_OUTPUT_HANDLE);
	}

	return pr_res;
}

i32 _EPrint(void const *str)
{
	return _Write(str, STD_ERROR_HANDLE);
}

i32 _EPrintf(const char *fmt, va_list arg)
{
	char buffer[1024];

	int sprf_res = stbsp_vsnprintf(&buffer[0], 1024, fmt, arg);

	if (sprf_res < 0) return sprf_res;

	return EPrint(&buffer);
}

b32 CreatePlatformWindow(const char *window_name)
{
	b32 success = true;

	WNDCLASS window_class = {
		.style = CS_OWNDC|CS_HREDRAW|CS_VREDRAW,
		.lpfnWndProc = WindowProc,
		.hInstance = win32_instance,
		.lpszClassName = WINDOW_CLASS_NAME,
	};

	ATOM r_class_atom = RegisterClass(&window_class);
	if (!r_class_atom)
		success = false;

	if (success)
	{
		HWND window_handle = CreateWindowExA(
			0,
			window_class.lpszClassName,
			window_name,
			WS_OVERLAPPEDWINDOW|WS_VISIBLE,
			CW_USEDEFAULT,
			CW_USEDEFAULT,
			CW_USEDEFAULT,
			CW_USEDEFAULT,
			0,
			0,
			win32_instance,
			0
		);

		if (!window_handle)
			success = false;
		else
			win32_window.handle = window_handle;
	}

	return success;
}

PlatformWindow *GetPlatformWindow()
{
	return &win32_window;
}

void GetWindowEvents()
{
	BOOL has_msg = false;
	MSG message;
	do 
	{
		has_msg = PeekMessage(&message, 0, 0, 0, PM_REMOVE);
		if (has_msg > 0)
		{
			TranslateMessage(&message);
			DispatchMessage(&message);
		}
	}
	while (has_msg);
}

void WaitForWindowEvent()
{
	MSG message;
	BOOL message_result = GetMessageA(&message, 0, 0, 0);
	if (message_result > 0)
	{
		TranslateMessage(&message);
		DispatchMessage(&message);
	}
}

b32 ShouldQuit()
{
	return global_quit;
}

WindowSize _GetWindowSize()
{
	return (WindowSize){ .w = win32_window.w, .h = win32_window.h };
}

