#include <extra2d/graphics/backends/opengl/gl_font_atlas.h>
#include <extra2d/utils/logger.h>

#include <algorithm>
#include <cmath>
#include <cstring>
#include <fstream>

// 在实现文件中定义 STB 实现
#define STB_TRUETYPE_IMPLEMENTATION
#include <stb/stb_truetype.h>

#define STB_RECT_PACK_IMPLEMENTATION
#include <stb/stb_rect_pack.h>

namespace extra2d {

// ============================================================================
// GLFontAtlas 构造函数
// 加载字体文件并初始化图集
// ============================================================================
GLFontAtlas::GLFontAtlas(const std::string &filepath, int fontSize, bool useSDF)
    : useSDF_(useSDF), fontSize_(fontSize), lineHeight_(0.0f), ascent_(0.0f),
      descent_(0.0f), lineGap_(0.0f), scale_(0.0f) {

  // 加载字体文件
  if (!initFont(filepath)) {
    E2D_LOG_ERROR("Failed to initialize font: {}", filepath);
    return;
  }

  // 计算字体缩放比例和度量
  scale_ = stbtt_ScaleForPixelHeight(&fontInfo_, static_cast<float>(fontSize_));

  int ascent, descent, lineGap;
  stbtt_GetFontVMetrics(&fontInfo_, &ascent, &descent, &lineGap);

  ascent_ = static_cast<float>(ascent) * scale_;
  descent_ = static_cast<float>(descent) * scale_;
  lineGap_ = static_cast<float>(lineGap) * scale_;
  lineHeight_ = ascent_ - descent_ + lineGap_;

  // 创建图集纹理和打包上下文
  createAtlas();

  // 预加载常用 ASCII 字符
  std::string asciiChars = " !\"#$%&'()*+,-./"
                           "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
                           "abcdefghijklmnopqrstuvwxyz{|}~";
  for (char c : asciiChars) {
    char32_t codepoint = static_cast<char32_t>(static_cast<unsigned char>(c));
    cacheGlyph(codepoint);
  }

  E2D_LOG_INFO("Font atlas created: {} ({}px, {}x{})", filepath, fontSize_,
               ATLAS_WIDTH, ATLAS_HEIGHT);
}

// ============================================================================
// GLFontAtlas 析构函数
// ============================================================================
GLFontAtlas::~GLFontAtlas() {
  // 智能指针自动管理纹理资源
}

// ============================================================================
// 获取字形信息 - 如果字形不存在则动态缓存
// ============================================================================
const Glyph *GLFontAtlas::getGlyph(char32_t codepoint) const {
  auto it = glyphs_.find(codepoint);
  if (it == glyphs_.end()) {
    // 动态缓存新字形
    const_cast<GLFontAtlas *>(this)->cacheGlyph(codepoint);
    it = glyphs_.find(codepoint);
    if (it == glyphs_.end()) {
      return nullptr;
    }
  }

  // 返回静态存储的 Glyph 数据
  static Glyph glyph;
  const auto &data = it->second;
  glyph.width = data.width;
  glyph.height = data.height;
  glyph.bearingX = data.bearingX;
  glyph.bearingY = data.bearingY;
  glyph.advance = data.advance;
  glyph.u0 = data.u0;
  glyph.v0 = data.v0;
  glyph.u1 = data.u1;
  glyph.v1 = data.v1;

  return &glyph;
}

// ============================================================================
// 测量文本尺寸 - 支持多行文本
// ============================================================================
Vec2 GLFontAtlas::measureText(const std::string &text) {
  float width = 0.0f;
  float maxWidth = 0.0f;
  float height = lineHeight_;
  float currentWidth = 0.0f;

  for (size_t i = 0; i < text.length();) {
    // 处理 UTF-8 编码
    char32_t codepoint = 0;
    unsigned char c = static_cast<unsigned char>(text[i]);

    if ((c & 0x80) == 0) {
      // 单字节 ASCII
      codepoint = c;
      i++;
    } else if ((c & 0xE0) == 0xC0) {
      // 2字节 UTF-8
      if (i + 1 >= text.length())
        break;
      codepoint =
          ((c & 0x1F) << 6) | (static_cast<unsigned char>(text[i + 1]) & 0x3F);
      i += 2;
    } else if ((c & 0xF0) == 0xE0) {
      // 3字节 UTF-8
      if (i + 2 >= text.length())
        break;
      codepoint = ((c & 0x0F) << 12) |
                  ((static_cast<unsigned char>(text[i + 1]) & 0x3F) << 6) |
                  (static_cast<unsigned char>(text[i + 2]) & 0x3F);
      i += 3;
    } else if ((c & 0xF8) == 0xF0) {
      // 4字节 UTF-8
      if (i + 3 >= text.length())
        break;
      codepoint = ((c & 0x07) << 18) |
                  ((static_cast<unsigned char>(text[i + 1]) & 0x3F) << 12) |
                  ((static_cast<unsigned char>(text[i + 2]) & 0x3F) << 6) |
                  (static_cast<unsigned char>(text[i + 3]) & 0x3F);
      i += 4;
    } else {
      // 无效的 UTF-8，跳过
      i++;
      continue;
    }

    // 处理换行
    if (codepoint == '\n') {
      maxWidth = std::max(maxWidth, currentWidth);
      currentWidth = 0.0f;
      height += lineHeight_;
      continue;
    }

    const Glyph *glyph = getGlyph(codepoint);
    if (glyph) {
      currentWidth += glyph->advance;
    }
  }

  maxWidth = std::max(maxWidth, currentWidth);
  return Vec2(maxWidth, height);
}

// ============================================================================
// 初始化字体 - 加载字体文件到内存
// ============================================================================
bool GLFontAtlas::initFont(const std::string &filepath) {
  // 读取字体文件到内存
  std::ifstream file(filepath, std::ios::binary | std::ios::ate);
  if (!file.is_open()) {
    E2D_LOG_ERROR("Failed to open font file: {}", filepath);
    return false;
  }

  std::streamsize size = file.tellg();
  file.seekg(0, std::ios::beg);

  fontData_.resize(static_cast<size_t>(size));
  if (!file.read(reinterpret_cast<char *>(fontData_.data()), size)) {
    E2D_LOG_ERROR("Failed to read font file: {}", filepath);
    return false;
  }

  // 初始化 STB 字体
  if (!stbtt_InitFont(&fontInfo_, fontData_.data(), 0)) {
    E2D_LOG_ERROR("Failed to initialize STB font: {}", filepath);
    return false;
  }

  return true;
}

// ============================================================================
// 创建图集纹理 - 初始化空白纹理和矩形打包上下文
// ============================================================================
void GLFontAtlas::createAtlas() {
  // 统一使用 4 通道格式 (RGBA)
  int channels = 4;
  std::vector<uint8_t> emptyData(ATLAS_WIDTH * ATLAS_HEIGHT * channels, 0);
  texture_ = std::make_unique<GLTexture>(ATLAS_WIDTH, ATLAS_HEIGHT,
                                         emptyData.data(), channels);
  texture_->setFilter(true);

  // 初始化矩形打包上下文 - 持久化以支持增量打包
  packNodes_.resize(ATLAS_WIDTH);
  stbrp_init_target(&packContext_, ATLAS_WIDTH, ATLAS_HEIGHT, packNodes_.data(),
                    ATLAS_WIDTH);

  // 预分配字形缓冲区
  // 假设最大字形尺寸为 fontSize * fontSize * 4 (RGBA)
  size_t maxGlyphSize = static_cast<size_t>(fontSize_ * fontSize_ * 4 * 4);
  glyphBitmapCache_.reserve(maxGlyphSize);
  glyphRgbaCache_.reserve(maxGlyphSize);
}

// ============================================================================
// 缓存字形 - 渲染字形到图集并存储信息
// 使用 stb_rect_pack 进行矩形打包
// ============================================================================
void GLFontAtlas::cacheGlyph(char32_t codepoint) {
  // 检查是否已存在
  if (glyphs_.find(codepoint) != glyphs_.end()) {
    return;
  }

  // 获取字形水平度量
  int advance, leftSideBearing;
  stbtt_GetCodepointHMetrics(&fontInfo_, static_cast<int>(codepoint), &advance,
                             &leftSideBearing);
  float advancePx = static_cast<float>(advance) * scale_;

  // SDF 渲染模式
  if (useSDF_) {
    constexpr int SDF_PADDING = 8;
    constexpr unsigned char ONEDGE_VALUE = 128;
    constexpr float PIXEL_DIST_SCALE = 64.0f;

    int w = 0, h = 0, xoff = 0, yoff = 0;
    unsigned char *sdf = stbtt_GetCodepointSDF(
        &fontInfo_, scale_, static_cast<int>(codepoint), SDF_PADDING,
        ONEDGE_VALUE, PIXEL_DIST_SCALE, &w, &h, &xoff, &yoff);

    if (!sdf || w <= 0 || h <= 0) {
      if (sdf)
        stbtt_FreeSDF(sdf, nullptr);
      // 创建空白字形（如空格）
      GlyphData data{};
      data.advance = advancePx;
      glyphs_[codepoint] = data;
      return;
    }

    // 使用 stb_rect_pack 打包矩形
    stbrp_rect rect;
    rect.id = static_cast<int>(codepoint);
    rect.w = w + PADDING * 2;
    rect.h = h + PADDING * 2;

    stbrp_pack_rects(&packContext_, &rect, 1);
    if (!rect.was_packed) {
      E2D_LOG_WARN("Font atlas is full, cannot cache codepoint: {}", codepoint);
      stbtt_FreeSDF(sdf, nullptr);
      return;
    }

    int atlasX = rect.x + PADDING;
    int atlasY = rect.y + PADDING;

    // 创建字形数据
    GlyphData data;
    data.width = static_cast<float>(w);
    data.height = static_cast<float>(h);
    data.bearingX = static_cast<float>(xoff);
    data.bearingY = static_cast<float>(yoff);
    data.advance = advancePx;

    // 计算 UV 坐标
    // stb_rect_pack 使用左上角为原点，OpenGL纹理使用左下角为原点
    // 需要翻转V坐标
    float v0 = static_cast<float>(atlasY) / ATLAS_HEIGHT;
    float v1 = static_cast<float>(atlasY + h) / ATLAS_HEIGHT;
    data.u0 = static_cast<float>(atlasX) / ATLAS_WIDTH;
    data.v0 = 1.0f - v1; // 翻转V坐标
    data.u1 = static_cast<float>(atlasX + w) / ATLAS_WIDTH;
    data.v1 = 1.0f - v0; // 翻转V坐标

    glyphs_[codepoint] = data;

    // 将 SDF 单通道数据转换为 RGBA 格式（统一格式）
    size_t pixelCount = static_cast<size_t>(w) * static_cast<size_t>(h);
    glyphRgbaCache_.resize(pixelCount * 4);
    for (size_t i = 0; i < pixelCount; ++i) {
      uint8_t alpha = sdf[i];
      glyphRgbaCache_[i * 4 + 0] = 255;   // R
      glyphRgbaCache_[i * 4 + 1] = 255;   // G
      glyphRgbaCache_[i * 4 + 2] = 255;   // B
      glyphRgbaCache_[i * 4 + 3] = alpha; // A - SDF 值存储在 Alpha 通道
    }

    // 更新纹理 - OpenGL纹理坐标原点在左下角，需要将Y坐标翻转
    updateAtlas(atlasX, ATLAS_HEIGHT - atlasY - h, w, h, glyphRgbaCache_);

    stbtt_FreeSDF(sdf, nullptr);
    return;
  }

  // 普通位图渲染模式
  int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
  stbtt_GetCodepointBitmapBox(&fontInfo_, static_cast<int>(codepoint), scale_,
                              scale_, &x0, &y0, &x1, &y1);
  int w = x1 - x0;
  int h = y1 - y0;
  int xoff = x0;
  // y0 是相对于基线的偏移（通常为负值，表示在基线上方）
  // bearingY 应该是字形顶部相对于基线的偏移
  int yoff = y0;

  if (w <= 0 || h <= 0) {
    // 空白字符（如空格）
    GlyphData data{};
    data.advance = advancePx;
    glyphs_[codepoint] = data;
    return;
  }

  // 使用预分配缓冲区渲染字形
  size_t pixelCount = static_cast<size_t>(w) * static_cast<size_t>(h);
  glyphBitmapCache_.resize(pixelCount);
  stbtt_MakeCodepointBitmap(&fontInfo_, glyphBitmapCache_.data(), w, h, w,
                            scale_, scale_, static_cast<int>(codepoint));

  // 使用 stb_rect_pack 打包矩形
  stbrp_rect rect;
  rect.id = static_cast<int>(codepoint);
  rect.w = w + PADDING * 2;
  rect.h = h + PADDING * 2;

  stbrp_pack_rects(&packContext_, &rect, 1);

  if (!rect.was_packed) {
    E2D_LOG_WARN("Font atlas is full, cannot cache codepoint: {}", codepoint);
    return;
  }

  int atlasX = rect.x + PADDING;
  int atlasY = rect.y + PADDING;

  // 创建字形数据
  GlyphData data;
  data.width = static_cast<float>(w);
  data.height = static_cast<float>(h);
  data.bearingX = static_cast<float>(xoff);
  data.bearingY = static_cast<float>(yoff);
  data.advance = advancePx;

  // 计算 UV 坐标
  // stb_rect_pack 使用左上角为原点，OpenGL纹理使用左下角为原点
  // 需要翻转V坐标
  float v0 = static_cast<float>(atlasY) / ATLAS_HEIGHT;
  float v1 = static_cast<float>(atlasY + h) / ATLAS_HEIGHT;
  data.u0 = static_cast<float>(atlasX) / ATLAS_WIDTH;
  data.v0 = 1.0f - v1; // 翻转V坐标
  data.u1 = static_cast<float>(atlasX + w) / ATLAS_WIDTH;
  data.v1 = 1.0f - v0; // 翻转V坐标

  glyphs_[codepoint] = data;

  // 将单通道字形数据转换为 RGBA 格式（白色字形，Alpha 通道存储灰度）
  glyphRgbaCache_.resize(pixelCount * 4);
  for (size_t i = 0; i < pixelCount; ++i) {
    uint8_t alpha = glyphBitmapCache_[i];
    glyphRgbaCache_[i * 4 + 0] = 255;   // R
    glyphRgbaCache_[i * 4 + 1] = 255;   // G
    glyphRgbaCache_[i * 4 + 2] = 255;   // B
    glyphRgbaCache_[i * 4 + 3] = alpha; // A
  }

  // 更新纹理 - OpenGL纹理坐标原点在左下角，需要将Y坐标翻转
  updateAtlas(atlasX, ATLAS_HEIGHT - atlasY - h, w, h, glyphRgbaCache_);
}

// ============================================================================
// 更新图集纹理区域
// ============================================================================
void GLFontAtlas::updateAtlas(int x, int y, int width, int height,
                              const std::vector<uint8_t> &data) {
  if (texture_) {
    texture_->bind();
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA,
                    GL_UNSIGNED_BYTE, data.data());
  }
}

} // namespace extra2d
