#include "presentation/fonts/MenuFontAtlas.h"

#include <imgui.h>

#include <cmath>
#include <cstdint>
#include <string>

#include "foundation/diagnostics/Logger.h"
#include "presentation/localization/UiLocalizationService.h"
#include "presentation/fonts/generated/EmbeddedFontData.h"

namespace ta::presentation::fonts
{
    namespace
    {
        float g_scale_factor = 0.0f;
        std::uint64_t g_localization_revision = 0;
        ImFont* g_regular = nullptr;
        ImFont* g_bold = nullptr;

        enum class Script
        {
            Latin,
            ChineseSimplified,
            Japanese,
            Korean
        };

        Script current_script()
        {
            const std::string locale = ta::presentation::localization::current_locale_id();
            if (locale.rfind("zh", 0) == 0)
                return Script::ChineseSimplified;
            if (locale.rfind("ja", 0) == 0)
                return Script::Japanese;
            if (locale.rfind("ko", 0) == 0)
                return Script::Korean;
            return Script::Latin;
        }

        bool merge_font(ImGuiIO& io,
                        ImFont* target,
                        const std::string& path,
                        const float size,
                        const ImWchar* ranges)
        {
            if (!target || path.empty() || !ranges)
                return false;
            ImFontConfig config{};
            config.MergeMode = true;
            config.DstFont = target;
            config.Flags |= ImFontFlags_NoLoadError;
            return io.Fonts->AddFontFromFileTTF(path.c_str(), size, &config, ranges) != nullptr;
        }

        void merge_selected_system_font(ImGuiIO& io,
                                        const float regular_size,
                                        const float bold_size,
                                        const ta::application::SystemFontPaths& system_fonts)
        {
            const std::string* path = nullptr;
            const ImWchar* ranges = nullptr;
            const char* script_name = nullptr;

            switch (current_script())
            {
            case Script::ChineseSimplified:
                path = &system_fonts.chinese;
                ranges = io.Fonts->GetGlyphRangesChineseSimplifiedCommon();
                script_name = "Chinese";
                break;
            case Script::Japanese:
                path = &system_fonts.japanese;
                ranges = io.Fonts->GetGlyphRangesJapanese();
                script_name = "Japanese";
                break;
            case Script::Korean:
                path = &system_fonts.korean;
                ranges = io.Fonts->GetGlyphRangesKorean();
                script_name = "Korean";
                break;
            case Script::Latin:
                return;
            }

            if (!path || path->empty())
            {
                ta::foundation::logger::warn(std::string("No system ") + script_name +
                             " font found; some selected-language glyphs may be unavailable");
                return;
            }

            const bool regular_ok = merge_font(io, g_regular, *path, regular_size, ranges);
            const bool bold_ok = merge_font(io, g_bold, *path, bold_size, ranges);
            if (!regular_ok || !bold_ok)
                ta::foundation::logger::warn(std::string("Failed to merge system ") + script_name + " UI font");
        }

        void build(ImGuiIO& io, const float scale_factor, const ta::application::SystemFontPaths& system_fonts)
        {
            const float regular_size = 16.0f * scale_factor;
            const float bold_size = 18.0f * scale_factor;

            g_regular = io.Fonts->AddFontFromMemoryCompressedBase85TTF(
                poppins_regular_data, regular_size);
            g_bold = io.Fonts->AddFontFromMemoryCompressedTTF(
                bold_compressed_data, bold_compressed_size, bold_size);

            if (!g_regular || !g_bold)
                ta::foundation::logger::warn("Failed to load one or more embedded fonts");

            merge_selected_system_font(io, regular_size, bold_size, system_fonts);
            g_scale_factor = scale_factor;
            g_localization_revision = ta::presentation::localization::revision();
        }
    }

    void setup(ImGuiIO& io,
               const float scale_factor,
               const ta::application::SystemFontPaths& system_fonts)
    {
        build(io, scale_factor, system_fonts);
    }

    bool needs_rebuild(const float scale_factor) noexcept
    {
        return ta::presentation::localization::revision() != g_localization_revision ||
            std::fabs(scale_factor - g_scale_factor) > 0.001f;
    }

    void rebuild(ImGuiIO& io,
                 const float scale_factor,
                 const ta::application::SystemFontPaths& system_fonts)
    {
        io.Fonts->Clear();
        reset();
        build(io, scale_factor, system_fonts);
    }

    void reset() noexcept
    {
        g_regular = nullptr;
        g_bold = nullptr;
        g_scale_factor = 0.0f;
        g_localization_revision = 0;
    }

    ImFont* hud_font() noexcept
    {
        return g_regular;
    }

    ImFont* bold_font() noexcept
    {
        return g_bold;
    }
}
