#include "pch.h"

#include "platform_windows/windows_async_render_context.h"

#include "log.h"
#include "platform_windows/windows_bootstrap_helpers.h"

namespace pp::platform::windows {
namespace {

struct RetainedWin32AsyncRenderContextState final {
    HDC hdc{};
    HGLRC hrc{};
    std::mutex gl_mutex;
    std::thread::id gl_thread{};
    int gl_count = 0;
};

[[nodiscard]] RetainedWin32AsyncRenderContextState& retained_win32_async_render_context_state()
{
    static RetainedWin32AsyncRenderContextState state;
    return state;
}

}

void set_async_render_context(HDC hdc, HGLRC hrc)
{
    auto& state = retained_win32_async_render_context_state();
    state.hdc = hdc;
    state.hrc = hrc;
    state.gl_thread = {};
    state.gl_count = 0;
}

void lock_async_render_context()
{
    auto& state = retained_win32_async_render_context_state();
    if (state.gl_count == 0 || state.gl_thread != std::this_thread::get_id())
    {
        state.gl_mutex.lock();
        const bool ret = wglMakeCurrent(state.hdc, state.hrc);
        if (!ret)
            LOG("FAILED wglMakeCurrent: %s", pp::platform::windows::GetLastErrorAsString().c_str());
        state.gl_thread = std::this_thread::get_id();
    }
    state.gl_count++;
}

bool try_lock_async_render_context()
{
    auto& state = retained_win32_async_render_context_state();
    if (state.gl_count == 0 || state.gl_thread != std::this_thread::get_id())
    {
        if (!state.gl_mutex.try_lock())
            return false;
        const bool ret = wglMakeCurrent(state.hdc, state.hrc);
        if (!ret)
            LOG("FAILED wglMakeCurrent: %s", pp::platform::windows::GetLastErrorAsString().c_str());
        state.gl_thread = std::this_thread::get_id();
    }
    state.gl_count++;
    return true;
}

void unlock_async_render_context()
{
    auto& state = retained_win32_async_render_context_state();
    state.gl_count--;
    if (state.gl_count == 0)
    {
        wglMakeCurrent(0, 0);
        state.gl_mutex.unlock();
    }
}

void swap_async_render_context()
{
    SwapBuffers(retained_win32_async_render_context_state().hdc);
}

}
