//! Single-line text rasterization for forge's chrome, backed by ltk.
//!
//! ltk shapes the line (BiDi + rustybuzz) against its font fallback chain and
//! caches both the shaped run and the rasterized glyphs, so the scratch canvas
//! is kept alive across calls.

use ltk::Canvas as LtkCanvas;

/// Physical pixel size for a `logical` design size at `scale`, including the
/// accessibility text scale.
///
/// Callers pass the result to [`TextRenderer::render_line`] *and* use it in
/// whatever cache key guards that call: the two must be the same number, or a
/// cache serves a raster baked at a size that no longer applies.
pub fn text_px(logical: f32, scale: f64) -> f32 {
    logical * scale as f32 * ltk::text_scale()
}

pub struct TextRenderer {
    canvas: LtkCanvas,
}

impl TextRenderer {
    pub fn new() -> Self {
        Self { canvas: LtkCanvas::new(1, 1) }
    }

    /// Render a single line into a premultiplied RGBA buffer at `px` physical
    /// pixels. Returns (buffer, width, height).
    pub fn render_line(&mut self, text: &str, px: f32, color: [u8; 4]) -> (Vec<u8>, u32, u32) {
        if text.is_empty() || px <= 0.0 {
            return (Vec::new(), 0, 0);
        }

        let (advance, line_h) = ltk::measure_text(text, px);
        let width = advance.ceil().max(0.0) as u32 + 1;
        let height = line_h.ceil().max(0.0) as u32;
        if width <= 1 || height == 0 {
            return (Vec::new(), 0, 0);
        }

        let baseline = self
            .canvas
            .font_line_metrics(px)
            .map(|m| m.ascent)
            .unwrap_or(px);

        if self.canvas.size() != (width, height) {
            self.canvas.resize(width, height);
        }
        self.canvas.clear();
        self.canvas.draw_text(
            text,
            0.0,
            baseline,
            px,
            ltk::Color::rgba(
                color[0] as f32 / 255.0,
                color[1] as f32 / 255.0,
                color[2] as f32 / 255.0,
                color[3] as f32 / 255.0,
            ),
        );

        let mut buffer = vec![0u8; (width * height * 4) as usize];
        self.canvas.write_to_wayland_buf(&mut buffer, false);
        (buffer, width, height)
    }
}
