#include <Core/HAL/Display/Win32/Win32Window.h>
#include <Core/HAL/Display/Window.h>
#include <Core/ImGui/ImGuiService.h>
#include <Core/ImGui/ImGuiTests.h>
#include <Core/Logging/LogManager.h>
#include <Core/Memory/MemoryArena.h>

#ifdef JULIET_ENABLE_IMGUI

#include <backends/imgui_impl_win32.h>
#include <imgui.h>

#include <cstdio>

// Forward declare implementation functions from backends
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

namespace Juliet::ImGuiService
{
    namespace
    {
        ImGuiContext* g_ImGuiContext = nullptr;
        bool          g_Initialized  = false;

        // Dedicated Paged Arena for ImGui
        // Sharing the same underlying Engine Pool for blocks, but separate Arena chain.
        Arena* g_ImGuiArena = {};

        void* ImGuiAllocWrapper(size_t size, void* /*user_data*/)
        {
            return ArenaPush(g_ImGuiArena, size, 8, false JULIET_DEBUG_ONLY(, "ImGuiAlloc"));
        }

        void ImGuiFreeWrapper(void* /*ptr*/, void* /*user_data*/)
        {
            // TODO : Free list of imgui elements.
        }
    } // namespace

    void Initialize(NonNullPtr<Window> window)
    {
        Assert(!g_Initialized);

        // Initialize ImGui Arena using Engine Pool
        g_ImGuiArena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "ImGui"));

        // Setup Allocator
        ImGui::SetAllocatorFunctions(ImGuiAllocWrapper, ImGuiFreeWrapper, nullptr);

        IMGUI_CHECKVERSION();
        g_ImGuiContext = ImGui::CreateContext();
        ImGuiIO& io    = ImGui::GetIO();
        io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
        // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls

        ImGui::StyleColorsDark();

        // Platform Init
        auto* win32State = static_cast<Win32::Window32State*>(window->State);
        ImGui_ImplWin32_Init(win32State->Handle);

        g_Initialized = true;
    }

    void Shutdown()
    {
        Assert(g_Initialized);

        ImGui_ImplWin32_Shutdown();
        ImGui::DestroyContext(g_ImGuiContext);
        g_ImGuiContext = nullptr;
        g_Initialized  = false;
    }

    void NewFrame()
    {
        Assert(g_Initialized);

        ImGui_ImplWin32_NewFrame();
        ImGui::NewFrame();
    }

    void Render()
    {
        Assert(g_Initialized);

        ImGui::Render();
    }

    bool IsInitialized()
    {
        return g_Initialized;
    }

    ImGuiContext* GetContext()
    {
        return g_ImGuiContext;
    }

    void RunTests()
    {
        printf("ImGuiService: Running Unit Tests...\n");
        Juliet::UnitTest::TestImGui();
    }
} // namespace Juliet::ImGuiService

#endif // JULIET_ENABLE_IMGUI
