#include "adapters/windows/rendering/ImGuiHost.h"
#include "adapters/windows/rendering/RenderDiagnostics.h"

#include "application/contracts/IImGuiClient.h"
#include "adapters/windows/fonts/WindowsFontLocator.h"
#include "foundation/diagnostics/Logger.h"

#include <imgui.h>
#include <imgui_impl_dx11.h>
#include <imgui_impl_win32.h>

#include <optional>

namespace
{
    bool g_initialized = false;
    ta::application::IImGuiClient* g_client = nullptr;

    std::optional<ta::application::SystemFontPaths> resolve_system_fonts()
    {
        const auto chinese = ta::adapters::windows::fonts::find_system_font(L"msyh.ttc");
        const auto japanese = ta::adapters::windows::fonts::find_system_font(L"YuGothM.ttc");
        const auto korean = ta::adapters::windows::fonts::find_system_font(L"malgun.ttf");
        if (!chinese || !japanese || !korean)
        {
            ta::foundation::logger::error(
                "UI", "Required system font unavailable: msyh.ttc, YuGothM.ttc or malgun.ttf");
            return std::nullopt;
        }
        return ta::application::SystemFontPaths{*chinese, *japanese, *korean};
    }
}

namespace ta::adapters::windows::rendering::imgui_host
{
    bool init(HWND window, ID3D11Device* device, ID3D11DeviceContext* context, ta::application::IImGuiClient& client) noexcept
    {
        if (g_initialized)
            return true;

        if (!window || !device || !context)
            return false;

        IMGUI_CHECKVERSION();
        ImGui::CreateContext();

        if (!ImGui_ImplWin32_Init(window))
        {
            ImGui::DestroyContext();
            return false;
        }

        if (!ImGui_ImplDX11_Init(device, context))
        {
            ImGui_ImplWin32_Shutdown();
            ImGui::DestroyContext();
            return false;
        }

        const auto system_fonts = resolve_system_fonts();
        if (!system_fonts)
        {
            ImGui_ImplDX11_Shutdown();
            ImGui_ImplWin32_Shutdown();
            ImGui::DestroyContext();
            return false;
        }

        g_client = &client;
        g_client->setup(*system_fonts);
        g_initialized = true;
        ta::adapters::windows::rendering::diagnostics::set_imgui_initialized(true);
        return true;
    }

    void new_frame() noexcept
    {
        if (!g_initialized)
            return;

        const float scale_factor = g_client ? g_client->scale_factor() : 1.0f;
        if (g_client && g_client->needs_font_rebuild(scale_factor))
        {
            ImGui_ImplDX11_InvalidateDeviceObjects();
            g_client->rebuild_fonts(scale_factor);
            if (!ImGui_ImplDX11_CreateDeviceObjects())
                ta::foundation::logger::warn("DX11 font atlas rebuild failed");
        }

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

    void draw() noexcept
    {
        if (!g_initialized)
            return;

        if (g_client)
            g_client->draw();
        ImGui::EndFrame();
        ImGui::Render();
    }

    void render_draw_data() noexcept
    {
        if (!g_initialized)
            return;

        ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
    }

    void shutdown() noexcept
    {
        if (!g_initialized)
            return;

        if (g_client)
            g_client->reset_render_resources();
        g_client = nullptr;
        ImGui_ImplDX11_Shutdown();
        ImGui_ImplWin32_Shutdown();
        ImGui::DestroyContext();
        g_initialized = false;
        ta::adapters::windows::rendering::diagnostics::set_imgui_initialized(false);
    }

    bool initialized() noexcept
    {
        return g_initialized;
    }

    bool menu_active() noexcept
    {
        return g_client && g_client->is_active();
    }
}
