#include "renderer_text.h"

#include <future>
#include <utility>
#include <spdlog/spdlog.h>

#include "renderer.h"
#include "renderer_texture_array.h"

#define STB_TRUETYPE_IMPLEMENTATION
#include <stb_truetype.h>

#include "misc/scope_exit.h"

// 在SDFFontCache.cpp中添加实现
const std::u32string aorii_text::COMMON_ASCII =
    U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

const std::u32string aorii_text::COMMON_CHINESE =
    U"的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严";

const std::u32string aorii_text::COMMON_PUNCTUATION =
    U"，。！？：；''""《》【】（）、";

const std::u32string aorii_text::COMMON_NUMBERS =
    U"0123456789";

aorii_text::font_data::~font_data() {
    delete font;
}

aorii_text::aorii_text() : texture_array(nullptr),
                           current_x(0), current_y(0),
                           current_texture_index(0) {
}

aorii_text::~aorii_text() {
}

bool aorii_text::init_freetype() {
    return true;
}

void aorii_text::destroy_freetype() {
}

bool aorii_text::initialize(const std::wstring& in_font_path) {
    // 预计需要的纹理数量(8张纹理几乎可以容纳所有字符)
    constexpr uint32_t expected_textures = 8;
    texture_array = aorii::get_renderer_raw()->create_texture_array(2048, 2048, expected_textures, texture_format::R8_UNORM, device_memory_type::gpu);
    if (!texture_array) {
        spdlog::error("无法创建字符缓冲纹理");
        return false;
    }

    if (!add_font(in_font_path)) {
        spdlog::error("添加主要字体失败");
        return false;
    }

    return true;
}

float aorii_text::get_kerning(char32_t ch1, char32_t ch2) const {
    font_data const* left_ch_font = nullptr;
    int g1 = 0, g2 = 0;

    // 在所有字体中查找字符对的字距调整
    for (const auto& font : fonts) {
        g1 = stbtt_FindGlyphIndex(font.font, ch1);
        g2 = stbtt_FindGlyphIndex(font.font, ch2);

        if (g1 != 0) {
            left_ch_font = &font;
        }
        if (g1 != 0 && g2 != 0) {
            return stbtt_GetGlyphKernAdvance(font.font, g1, g2);
        }
    }
    if (!left_ch_font)
        return 0.0f;

    int x0, x1;
    stbtt_GetGlyphBox(left_ch_font->font, g1, &x0, nullptr, &x1, nullptr);
    return x1 - x0;
}

bool aorii_text::add_font(const std::wstring& font_path) {
    font_data new_font{};
    new_font.font = new stbtt_fontinfo();

    // 映射字体文件
    if (!new_font.file.map_file(font_path)) {
        delete new_font.font;
        spdlog::error("Failed to map font file");
        return false;
    }

    const auto* font_buffer = static_cast<uint8_t*>(new_font.file.get_data());
    if (!stbtt_InitFont(new_font.font, font_buffer, stbtt_GetFontOffsetForIndex(font_buffer, 0))) {
        new_font.file.unmap();
        delete new_font.font;
        spdlog::error("Failed to initialize font");
        return false;
    }

    int temp_space_width, temp_tab_width;
    stbtt_GetCodepointHMetrics(new_font.font, ' ', &temp_space_width, nullptr);
    stbtt_GetCodepointHMetrics(new_font.font, '\t', &temp_tab_width, nullptr);
    new_font.space_width = temp_space_width;
    new_font.tab_width = temp_tab_width;

    int ascent, descent, line_gap;
    stbtt_GetFontVMetrics(new_font.font, &ascent, &descent, &line_gap);
    new_font.ascent = ascent;
    new_font.descent = descent;
    new_font.line_gap = line_gap;

    fonts.emplace_back(std::move(new_font));
    return true;
}

ch_atlas_item const* aorii_text::get_atlas_item(const char32_t ch) {
    if (const auto it = character_map.find(ch); it != character_map.end()) {
        return &it->second;
    }
    return cache_ch_to_atlas(ch);
}

bool aorii_text::precache_characters(const std::u32string& characters) {
    // 创建进度通知回调的函数指针类型
    using ProgressCallback = std::function<void(float progress, const wchar_t currentChar)>;

    bool success = true;

    // 使用线程池并行生成SDF数据
    const size_t max_threads = std::thread::hardware_concurrency();
    std::vector<std::future<std::vector<uint8_t>>> futures;
    std::mutex map_mutex;

    for (size_t i = 0; i < characters.length(); i++) {
        auto ch = characters[i];
        if (!get_atlas_item(ch))
            spdlog::error("Failed to create character U+{:04X}", (uint32_t)ch);
    }

    return success;
}

bool aorii_text::precache_common_characters() {
    std::u32string all_common_chars;
    all_common_chars.reserve(COMMON_ASCII.length() +
                          COMMON_CHINESE.length() +
                          COMMON_PUNCTUATION.length() +
                          COMMON_NUMBERS.length());

    all_common_chars += COMMON_ASCII;
    all_common_chars += COMMON_CHINESE;
    all_common_chars += COMMON_PUNCTUATION;
    all_common_chars += COMMON_NUMBERS;

    return precache_characters(all_common_chars);
}

uint32_t aorii_text::get_font_char_count() const {
    uint32_t result = 0;
    for (const auto& font : fonts) {
        result += font.font->numGlyphs;
    }
    return result;
}

uint32_t aorii_text::get_texture_size() const {
    return texture_array->size().x();
}

std::vector<measured_ch> aorii_text::measure_text(const std::u32string& text, float height) {
    // 获取主字体
    font_data const& primary_font = fonts[0];
    const float scale = stbtt_ScaleForPixelHeight(primary_font.font, height);
    const float scale_padding = padding * (height / pixel_height);

    // 基线和行高信息
    const int32_t ascent = primary_font.ascent;
    const int32_t descent = primary_font.descent;
    const float line_gap = primary_font.line_gap * scale;
    const float line_height = height;
    const float space_width = primary_font.space_width * scale;
    const float tab_width = primary_font.tab_width * scale;

    struct line_data {
        std::u32string text;
        int32_t max_top{};
        int32_t min_top{};
        int32_t max_bottom{};
        int32_t min_bottom{};
    };
    std::vector<line_data> lines;
    // 按照\n分割文本
    std::u32string text_copy = text;
    for (size_t i = 0; i < text_copy.length(); i++) {
        if (text_copy[i] == U'\n') {
            lines.emplace_back(text_copy.substr(0, i));
            text_copy = text_copy.substr(i + 1);
            i = 0;
        }
    }
    if (!text_copy.empty())
        lines.emplace_back(text_copy);

    for (auto& data: lines) {
        int32_t min_top = 0;
        int32_t min_bottom = 0;
        int32_t max_top = 0;
        int32_t max_bottom = 0;
        for (const auto& ch: data.text) {
            const auto item = get_atlas_item(ch);
            if (!item)
                continue;
            min_top = std::min(min_top, item->top);
            min_bottom = std::min(min_bottom, item->bottom);
            max_top = std::max(max_top, item->top);
            max_bottom = std::max(max_bottom, item->bottom);
        }
        data.min_top = min_top;
        data.min_bottom = min_bottom;
        data.max_top = max_top;
        data.max_bottom = max_bottom;
        // 如果min_top小于0, 则将max_bottom减去min_top
        // if (min_top < 0) {
        //     data.max_bottom -= min_top;
        //     data.min_bottom -= min_top;
        //     data.max_top -= min_top;
        //     data.min_top = 0;
        // }
    }

    std::vector<measured_ch> result;
    Eigen::Vector2f pos{0, 0};

    for (const auto& line : lines) {
        // 计算这一行顶部和底部的最大和最小值，然后进行垂直居中
        const float top_offset = (line_height - (line.max_bottom - line.min_top) * scale) / 2;

        for (const auto& ch : line.text) {
            if (ch == U' ') {
                pos.x() += space_width;
                continue;
            }
            if (ch == U'\t') {
                pos.x() += tab_width;
                continue;
            }

            const auto item = get_atlas_item(ch);
            measured_ch mch{};
            mch.item = item;
            mch.offset = pos;
            mch.size_scale = scale;
            if (item) {
                // 如果字符高度大于行高, 则缩放
                const float item_height = item->get_height() * scale;
                if (item_height > line_height) {
                    mch.size_scale = line_height / item_height * scale;
                }

                // 将字符底部对齐到行底部
                const float bottom_offset = item->bottom - line.max_bottom;
                mch.offset.y() -= bottom_offset * mch.size_scale;
                // mch.offset.y() += line_height;

                mch.offset.y() += top_offset;
                // mch.offset.x() += item->left * mch.size_scale;

                pos.x() += item->x_advance * mch.size_scale;
                // pos.x() -= item->left * mch.size_scale;
            }
            result.push_back(mch);
        }

        pos.x() = 0;
        pos.y() += line_height;
        pos.y() += line_gap;
        // pos.y() -= scale_padding * 2;
    }
    return result;
}

ch_atlas_item const* aorii_text::cache_ch_to_atlas(char32_t ch) {
    font_data const* current_font = nullptr;
    int glyph_index = 0;
    for (const auto& font : fonts) {
        glyph_index = stbtt_FindGlyphIndex(font.font, ch);
        if (glyph_index) {
            current_font = &font;
            break;
        }
    }
    if (!current_font) {
        return nullptr;
    }
    const auto font = current_font->font;
    const uint32_t texture_size = get_texture_size();

    constexpr uint8_t on_edge_value = 128;
    const float pixel_dist_scale = (float)on_edge_value / padding;
    const float scale = stbtt_ScaleForPixelHeight(font, pixel_height - padding * 2);

    // 获取SDF尺寸和位图
    int32_t width, height, x_offset, y_offset;
    auto* sdf_bitmap = stbtt_GetGlyphSDF(
        font,
        scale,
        glyph_index,
        padding,
        on_edge_value,
        pixel_dist_scale,
        &width, &height,
        &x_offset, &y_offset
    );

    if (!sdf_bitmap) {
        return nullptr;
    }
    ON_SCOPE_EXIT {
        stbtt_FreeSDF(sdf_bitmap, font->userdata);
    };

    // 检查当前行是否有足够空间
    if (current_x + width > texture_size) {
        // 移动到下一行
        current_x = 0;
        current_y = next_row_y;
    }

    // 检查是否需要新的纹理
    if (current_y + height > texture_size) {
        current_texture_index++;
        if (current_texture_index >= texture_array->get_count()) {
            spdlog::error("Texture array capacity exceeded");
            return nullptr;
        }
        current_x = 0;
        current_y = 0;
        next_row_y = 0;
    }

    // 更新纹理
    Eigen::AlignedBox2i box;
    box.min() = Eigen::Vector2i(current_x, current_y);
    box.max() = Eigen::Vector2i(current_x + width, current_y + height);

    texture_array->update_subresource(current_texture_index, box, sdf_bitmap, width);

    // 获取字形度量信息
    int advance_width, left_side_bearing;
    stbtt_GetGlyphHMetrics(font, glyph_index, &advance_width, &left_side_bearing);
    int ch_x0, ch_y0, ch_x1, ch_y1;
    stbtt_GetGlyphBox(font, glyph_index, &ch_x0, &ch_y0, &ch_x1, &ch_y1);

    int width_log = ch_x1 - ch_x0;
    int height_log = ch_y1 - ch_y0;
    spdlog::info("left: {}, right: {}, top: {}, bottom: {}, width: {}, height: {}, x_advance: {}, left_side_bearing: {}",
                 ch_x0, ch_x1, ch_y0, ch_y1, width_log, height_log, advance_width, left_side_bearing);

    // 将x_offset和y_offset转换到字体空间
    x_offset = x_offset / scale;
    y_offset = y_offset / scale;

    // 创建并存储字符信息
    ch_atlas_item info{};
    info.tex_u = current_x / static_cast<float>(texture_size);
    info.tex_v = current_y / static_cast<float>(texture_size);
    info.tex_z = static_cast<float>(current_texture_index);
    info.u_size = width / static_cast<float>(texture_size);
    info.v_size = height / static_cast<float>(texture_size);

    info.x_offset = x_offset;
    info.y_offset = y_offset;

    info.left = ch_x0;
    info.right = ch_x1;
    info.top = ch_y0;
    info.bottom = ch_y1;

    info.x_advance = advance_width;
    info.left_side_bearing = left_side_bearing;

    // 更新位置和下一行的y坐标
    current_x += width;
    next_row_y = std::max(next_row_y, current_y + height);

    return &(character_map[ch] = info);
}