//! 基于 FreeType 的中文文字光栅化 + OpenGL 纹理渲染（设备端 Live2D 字幕 overlay）。
//!
//! 设计：每个字符首次出现时用 FreeType 渲染为灰度位图（经 `render_glyph` 拿到位图），转成
//! 白色字形（alpha=灰度）的 RGBA 纹理并缓存；绘制时按 pen 位置贴纹理即可。纹理创建需要
//! `Gl` 函数指针（与渲染器共用同一 EGL 上下文）。

use super::gl::gl as gl_const;
use super::gl::Gl;
use freetype::face::LoadFlag;
use freetype::Face;
use freetype::Library;
use freetype::RenderMode;
use std::collections::HashMap;
use std::path::Path;

use anyhow::Result;

/// 单个字符的缓存字形
#[derive(Clone)]
pub struct CachedGlyph {
    /// 字形纹理（0 表示该字符无可见像素，仅用于步进）
    pub tex: gl_const::GLuint,
    pub w: i32,
    pub h: i32,
    /// 字形位图相对 pen 原点的偏移
    pub left: i32,
    pub top: i32,
    /// 26.6 定点像素步进（渲染端需 >> 6 转为像素）
    pub advance: i32,
}

pub struct TextRenderer {
    face: Face<'static>,
    font_px: u32,
    glyphs: HashMap<char, CachedGlyph>,
    white_tex: Option<gl_const::GLuint>,
}

// FreeType 的 Face 包裹裸指针，仅在本插件单一渲染线程使用。
unsafe impl Send for TextRenderer {}

/// FT_LOAD_RENDER 标志位（0x4）：加载字符的同时渲染为位图
const FT_LOAD_RENDER: i32 = 0x4;

impl TextRenderer {
    pub fn new(font_path: &Path, font_px: u32) -> Result<Self> {
        let library = Library::init()?;
        // 让 Library 成为 'static（程序级单例），从而 Face<'static> 可长期持有而不会悬垂
        let library: &'static Library = Box::leak(Box::new(library));
        let face = library.new_face(font_path, 0)?;
        let tr = Self {
            face,
            font_px,
            glyphs: HashMap::new(),
            white_tex: None,
        };
        tr.face.set_pixel_sizes(0, font_px)?;
        println!("[Live2D] 字幕字体就绪: {:?} ({}px)", font_path, font_px);
        Ok(tr)
    }

    /// 当前字号（像素）
    pub fn font_size(&self) -> u32 {
        self.font_px
    }

    /// 1x1 白色纹理（用于纯色背景框，alpha 恒为 1）。
    fn white_tex(&mut self, gl: &Gl) -> gl_const::GLuint {
        if let Some(t) = self.white_tex {
            return t;
        }
        let mut tex = 0u32;
        unsafe {
            (gl.gl_gen_textures)(1, &mut tex);
            (gl.gl_bind_texture)(gl_const::GL_TEXTURE_2D, tex);
            (gl.gl_tex_parameteri)(
                gl_const::GL_TEXTURE_2D,
                gl_const::GL_TEXTURE_MIN_FILTER,
                gl_const::GL_LINEAR as i32,
            );
            (gl.gl_tex_parameteri)(
                gl_const::GL_TEXTURE_2D,
                gl_const::GL_TEXTURE_MAG_FILTER,
                gl_const::GL_LINEAR as i32,
            );
            (gl.gl_tex_parameteri)(
                gl_const::GL_TEXTURE_2D,
                gl_const::GL_TEXTURE_WRAP_S,
                gl_const::GL_CLAMP_TO_EDGE as i32,
            );
            (gl.gl_tex_parameteri)(
                gl_const::GL_TEXTURE_2D,
                gl_const::GL_TEXTURE_WRAP_T,
                gl_const::GL_CLAMP_TO_EDGE as i32,
            );
            let px: [u8; 4] = [255, 255, 255, 255];
            (gl.gl_tex_image_2d)(
                gl_const::GL_TEXTURE_2D,
                0,
                gl_const::GL_RGBA as i32,
                1,
                1,
                0,
                gl_const::GL_RGBA,
                gl_const::GL_UNSIGNED_BYTE,
                px.as_ptr() as *const std::ffi::c_void,
            );
        }
        self.white_tex = Some(tex);
        tex
    }

    /// 取 1x1 白纹理（供外部画背景框）。
    pub fn white_texture(&mut self, gl: &Gl) -> gl_const::GLuint {
        self.white_tex(gl)
    }

    /// 估算字符像素宽度（用于换行布局，不创建纹理）。返回像素值。
    pub fn measure_advance(&mut self, ch: char) -> i32 {
        if self
            .face
            .load_char(ch as usize, LoadFlag::from_bits_truncate(FT_LOAD_RENDER))
            .is_ok()
        {
            (self.face.glyph().advance().x >> 6) as i32
        } else {
            (self.font_px as f32 * 0.5) as i32
        }
    }

    fn rasterize(&mut self, gl: &Gl, ch: char) -> Option<CachedGlyph> {
        let half_advance_26_6 = (self.font_px as i32) << 5; // 半字宽，26.6 定点
        if self
            .face
            .load_char(ch as usize, LoadFlag::from_bits_truncate(FT_LOAD_RENDER))
            .is_err()
        {
            return Some(CachedGlyph {
                tex: 0,
                w: 0,
                h: 0,
                left: 0,
                top: 0,
                advance: half_advance_26_6,
            });
        }
        let glyph = self.face.glyph();
        if glyph.render_glyph(RenderMode::Normal).is_err() {
            let adv = glyph.advance().x as i32; // 26.6 定点
            return Some(CachedGlyph {
                tex: 0,
                w: 0,
                h: 0,
                left: 0,
                top: 0,
                advance: adv,
            });
        }
        let bitmap = glyph.bitmap();
        let w = bitmap.width();
        let h = bitmap.rows();
        let left = glyph.bitmap_left();
        let top = glyph.bitmap_top();
        let advance = glyph.advance().x as i32; // 26.6 定点
        if w == 0 || h == 0 {
            return Some(CachedGlyph {
                tex: 0,
                w: 0,
                h: 0,
                left,
                top,
                advance,
            });
        }
        // 灰度 -> RGBA：白色字形，alpha=灰度
        let buf = bitmap.buffer();
        let mut rgba: Vec<u8> = Vec::with_capacity((w * h * 4) as usize);
        for &g in buf {
            rgba.push(255);
            rgba.push(255);
            rgba.push(255);
            rgba.push(g);
        }
        let mut tex = 0u32;
        unsafe {
            (gl.gl_gen_textures)(1, &mut tex);
            (gl.gl_bind_texture)(gl_const::GL_TEXTURE_2D, tex);
            (gl.gl_tex_parameteri)(
                gl_const::GL_TEXTURE_2D,
                gl_const::GL_TEXTURE_MIN_FILTER,
                gl_const::GL_LINEAR as i32,
            );
            (gl.gl_tex_parameteri)(
                gl_const::GL_TEXTURE_2D,
                gl_const::GL_TEXTURE_MAG_FILTER,
                gl_const::GL_LINEAR as i32,
            );
            (gl.gl_tex_parameteri)(
                gl_const::GL_TEXTURE_2D,
                gl_const::GL_TEXTURE_WRAP_S,
                gl_const::GL_CLAMP_TO_EDGE as i32,
            );
            (gl.gl_tex_parameteri)(
                gl_const::GL_TEXTURE_2D,
                gl_const::GL_TEXTURE_WRAP_T,
                gl_const::GL_CLAMP_TO_EDGE as i32,
            );
            (gl.gl_tex_image_2d)(
                gl_const::GL_TEXTURE_2D,
                0,
                gl_const::GL_RGBA as i32,
                w,
                h,
                0,
                gl_const::GL_RGBA,
                gl_const::GL_UNSIGNED_BYTE,
                rgba.as_ptr() as *const std::ffi::c_void,
            );
        }
        Some(CachedGlyph {
            tex,
            w,
            h,
            left,
            top,
            advance,
        })
    }

    /// 获取（必要时光栅化并缓存）字符字形。
    pub fn glyph(&mut self, gl: &Gl, ch: char) -> Option<CachedGlyph> {
        if !self.glyphs.contains_key(&ch) {
            if let Some(g) = self.rasterize(gl, ch) {
                self.glyphs.insert(ch, g);
            }
        }
        self.glyphs.get(&ch).cloned()
    }
}
