#include "pch.h"

#include "platform_windows/windows_runtime_session.h"

#include "app.h"
#include "log.h"
#include "platform_windows/windows_bootstrap_helpers.h"
#include "platform_windows/windows_lifecycle_state.h"
#include "platform_windows/windows_main_window_session.h"
#include "platform_windows/windows_platform_services.h"
#include "platform_windows/windows_runtime_shell.h"
#include "platform_windows/windows_runtime_state.h"
#include "wacom.h"
#include "../resource.h"

namespace pp::platform::windows {

namespace {

void register_touch_window(HWND hWnd)
{
    // link: https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-registertouchwindow
    if (RegisterTouchWindow(hWnd, 0) == 0)
    {
        LOG("RegisterTouchWindow error: %s", GetLastErrorAsString().c_str());
    }
}

void initialize_runtime_threads()
{
    auto* app = bound_app();
    auto* runtime = retained_bound_runtime();
    assert(runtime);
    mark_lifecycle_running();
    runtime->render_thread_start(*app);
    runtime->ui_thread_start(*app);
}

void install_debug_gl_callbacks()
{
#ifdef _DEBUG
    glad_set_pre_callback(_pre_call_callback);
    glad_set_post_callback(_post_call_callback);
#endif
}

void initialize_wintab(HWND hWnd, bool sandboxed)
{
    auto* tablet = bound_wacom_tablet();
    if (!sandboxed)
    {
        LOG("init WinTab");
        tablet->init(hWnd);
    }
    else
    {
        LOG("SKIP init WinTab");
    }
}

void set_main_window_icon(HWND hWnd)
{
    LOG("change icon");
    SendMessage(
        hWnd,
        WM_SETICON,
        ICON_SMALL,
        (LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1)));
}

void restore_window_placement(HWND hWnd, int show_command)
{
    WINDOWPLACEMENT wp;
    GetWindowPlacement(hWnd, &wp);
    wp.showCmd = show_command;
    SetWindowPlacement(hWnd, &wp);
}

void run_main_message_loop()
{
    MSG msg;
    auto* app = bound_app();
    LOG("start main loop");
    while (lifecycle_is_running())
    {
        auto present = app->animate || app->redraw ?
            PeekMessage(&msg, 0, 0, 0, PM_REMOVE) : GetMessage(&msg, 0, 0, 0);

        if (msg.message == WM_QUIT)
            mark_lifecycle_stopped();

        if (present)
        {
            DispatchMessage(&msg);
            TranslateMessage(&msg);
        }

        drain_main_thread_tasks();
    }
}

void shutdown_main_window_runtime(const MainWindowStartupState& startup, HINSTANCE hInst)
{
    retained_wacom_tablet().terminate();
    UnregisterClass(startup.window_class.lpszClassName, hInst);
    LogRemote::I.stop();
}

}

void run_main_window_runtime_session(const MainWindowStartupState& startup, bool start_in_vr, HINSTANCE instance, SplashScreen& splash)
{
    auto* app = bound_app();
    register_touch_window(retained_main_window_handle_ref());

    wglMakeCurrent(NULL, NULL);

    initialize_runtime_threads();
    install_debug_gl_callbacks();
    initialize_wintab(retained_main_window_handle_ref(), retained_main_window_sandboxed());
    set_main_window_icon(retained_main_window_handle_ref());

    app->ui_sync();
    restore_window_placement(retained_main_window_handle_ref(), startup.show_command);

    if (start_in_vr)
        app->vr_start();

    LOG("show main window");
    SetForegroundWindow(retained_main_window_handle_ref());

    splash.dismiss();

    run_main_message_loop();
    shutdown_main_window_runtime(startup, instance);
}

}
