#include "platform/platform.h"

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <malloc.h>

#include "imgui_impl_win32.h"

extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

struct PlatformWindow {
    HWND    hwnd;
    bool    should_close;
    int32_t width;
    int32_t height;
};

static PlatformWindow *g_current_window = nullptr;

static LRESULT CALLBACK win32_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    if (ImGui_ImplWin32_WndProcHandler(hwnd, msg, wparam, lparam))
        return true;

    switch (msg) {
    case WM_SIZE:
        if (g_current_window && wparam != SIZE_MINIMIZED) {
            g_current_window->width  = (int32_t)LOWORD(lparam);
            g_current_window->height = (int32_t)HIWORD(lparam);
        }
        return 0;
    case WM_CLOSE:
        if (g_current_window)
            g_current_window->should_close = true;
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_SYSCOMMAND:
        if ((wparam & 0xfff0) == SC_KEYMENU)
            return 0;
        break;
    }
    return DefWindowProcW(hwnd, msg, wparam, lparam);
}

PlatformWindow *platform_create_window(PlatformWindowDesc *desc)
{
    WNDCLASSEXW wc = {};
    wc.cbSize        = sizeof(wc);
    wc.style         = CS_CLASSDC;
    wc.lpfnWndProc   = win32_wndproc;
    wc.hInstance     = GetModuleHandleW(nullptr);
    wc.lpszClassName = L"autosample_wc";
    RegisterClassExW(&wc);

    int screen_w = GetSystemMetrics(SM_CXSCREEN);
    int screen_h = GetSystemMetrics(SM_CYSCREEN);
    int x = (screen_w - desc->width) / 2;
    int y = (screen_h - desc->height) / 2;

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

    int wchar_count = MultiByteToWideChar(CP_UTF8, 0, desc->title, -1, nullptr, 0);
    wchar_t *wtitle = (wchar_t *)_malloca(wchar_count * sizeof(wchar_t));
    MultiByteToWideChar(CP_UTF8, 0, desc->title, -1, wtitle, wchar_count);

    HWND hwnd = CreateWindowExW(
        0, wc.lpszClassName, wtitle,
        WS_OVERLAPPEDWINDOW,
        x, y,
        rect.right - rect.left,
        rect.bottom - rect.top,
        nullptr, nullptr, wc.hInstance, nullptr
    );

    _freea(wtitle);

    if (!hwnd)
        return nullptr;

    ShowWindow(hwnd, SW_SHOWDEFAULT);
    UpdateWindow(hwnd);

    PlatformWindow *window = new PlatformWindow();
    window->hwnd         = hwnd;
    window->should_close = false;
    window->width        = desc->width;
    window->height       = desc->height;

    g_current_window = window;
    return window;
}

void platform_destroy_window(PlatformWindow *window)
{
    if (!window) return;

    if (window->hwnd) {
        DestroyWindow(window->hwnd);
        UnregisterClassW(L"autosample_wc", GetModuleHandleW(nullptr));
    }

    if (g_current_window == window)
        g_current_window = nullptr;

    delete window;
}

bool platform_poll_events(PlatformWindow *window)
{
    MSG msg;
    while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
        if (msg.message == WM_QUIT) {
            window->should_close = true;
        }
    }
    return !window->should_close;
}

void platform_get_size(PlatformWindow *window, int32_t *w, int32_t *h)
{
    if (w) *w = window->width;
    if (h) *h = window->height;
}

void *platform_get_native_handle(PlatformWindow *window)
{
    return (void *)window->hwnd;
}
