///|
/// 将文本渲染为 RGBA 位图。
///
/// - `color`:字形颜色,打包 RGBA `0xRRGGBBAA`;字形像素不透明时 alpha 取 255。
/// - `scale`(可选,默认 1):点阵放大倍数,用最近邻放大。
/// - `provider`(可选,默认 `Ascii5x7`):字形提供者,内置 `Cjk16` 支持中文点阵。
/// - 字符间距 1 像素(按各字符单元宽度累加,支持中英文混排);
///   不支持的字形渲染为空白。
/// - 空文本返回 0×0 图像。
pub fn render_text(text : String, color : Int32, scale? : Int32) -> RgbaImage {
  // scale 的默认/归一化逻辑统一在 render_text_with 处理,这里只做转发
  // (MoonBit 可选参数不支持 option 透传,必须显式 match)
  match scale {
    Some(v) => render_text_with(text, color, Ascii5x7::new(), scale=v)
    None => render_text_with(text, color, Ascii5x7::new())
  }
}

///|
/// 带字形提供者的渲染(供自定义字形/`Cjk16` 使用)。
pub fn[T : GlyphProvider] render_text_with(
  text : String,
  color : Int32,
  provider : T,
  scale? : Int32,
) -> RgbaImage {
  let prov = provider
  let s = match scale {
    Some(v) => if v > 0 { v } else { 1 }
    None => 1
  }
  if text.length() == 0 {
    return RgbaImage::new(0, 0, 0)
  }
  let cw = prov.cell_width()
  let ch = prov.cell_height()
  // 游标式累计宽度:每个字符占 cw+1(1 像素间距),末尾去掉多余间距
  let mut w = 0
  for _, _ in text.iter2() {
    w = w + cw + 1
  }
  w = w - 1
  let img = RgbaImage::new(w * s, ch * s, 0x0000_0000)
  let mut x = 0
  for _, c in text.iter2() {
    match prov.glyph(c) {
      Some(g) => {
        // 每行字节数:5x7=1 字节/行,Cjk16(16宽)=2 字节/行。
        // 字形 cw 位在 bpr*8 位流中右对齐(左补 0),逐位定位,两种宽度通用。
        let bpr = g.length() / ch
        for row in 0..> (7 - within)) & 1) == 1 {
              for sy in 0.. ()
    }
    x = x + cw + 1
  }
  img
}

///|
/// 按 `font` 名称选择字形提供者渲染文本水印单元(embed_text / embed_tiled 共用)。
///
/// `font` 取 `"cjk16"`(中文点阵)或任意其他值(默认 ascii5x7 拉丁字形)。
fn render_text_by_font(
  text : String,
  color : Int32,
  font : String,
  font_size : Int32,
) -> RgbaImage {
  if font == "cjk16" {
    render_text_with(text, color, Cjk16::new(), scale=font_size)
  } else {
    render_text(text, color, scale=font_size)
  }
}

///|
/// 在图像指定位置叠加文本水印(原地修改并返回同一图像)。
///
/// 位置由 `TextConfig.x / y` 指定(水印左上角);透明度仅由
/// `opacity` 控制(字形像素不透明);`angle` 按度旋转(顺时针为正,
/// 0 = 不旋转,常用 45 做斜向防盗播水印)。
/// v0.1.11 起:水平/垂直文本(angle=0)越界不再静默裁剪——默认返回
/// `Err`,`auto_shrink=true` 时自动缩小字号适配画布;斜向文本(angle≠0)
/// 保留跨画布特性(45° 防盗播水印需要延伸出画布)。
pub fn RgbaImage::embed_text(
  self : RgbaImage,
  cfg : TextConfig,
) -> Result[RgbaImage, String] {
  // 超长文本会渲染出巨大位图(旋转时中间图按对角线尺寸分配,可至 GB 级):
  // 文本水印定位是短标记,超过 512 字符视为调用错误
  if cfg.text.length() > 512 {
    return Err("text too long: \{cfg.text.length()} chars (max 512)")
  }
  let mut wm = render_text_by_font(cfg.text, cfg.color, cfg.font, cfg.font_size)
  // v0.1.11:水平/垂直文本(angle=0)越界防护——文本超宽/超高不再被静默裁剪:
  // 默认返回错误;TextConfig.auto_shrink=true 时自动缩小字号适配画布。
  // 斜向文本(angle≠0)保留跨画布特性(45° 防盗播水印本就需要延伸出画布),不检查。
  if cfg.angle == 0.0 {
    let need_w = wm.width
    let need_h = wm.height
    let avail_w = self.width - cfg.x
    let avail_h = self.height - cfg.y
    if need_w > avail_w || need_h > avail_h {
      if cfg.auto_shrink == false {
        return Err(
          "text watermark exceeds image bounds: needs \{need_w}x\{need_h}, \{avail_w}x\{avail_h} available at (\{cfg.x}, \{cfg.y}); set TextConfig.auto_shrink=true to fit, or shorten text / reduce font_size",
        )
      }
      // auto_shrink:按两个方向所需缩放取最小值,重新渲染
      // 注意:font_size<=0 时 render_text_by_font 内部归一化为 scale=1,此处必须用
      // 同一归一化值反推格宽/格高,否则 font_size=0 会除零崩溃
      let base = if cfg.font_size > 0 { cfg.font_size } else { 1 }
      let c_w = need_w / base // 字符总格宽(n × cell_w,整除)
      let c_h = need_h / base // 单行格高(cell_h,整除)
      if avail_w <= 0 || avail_h <= 0 || c_w <= 0 || c_h <= 0 {
        return Err(
          "text watermark position out of image bounds: needs \{need_w}x\{need_h}, \{avail_w}x\{avail_h} available at (\{cfg.x}, \{cfg.y})",
        )
      }
      let s_w = avail_w / c_w
      let s_h = avail_h / c_h
      let s = if s_w < s_h { s_w } else { s_h }
      if s < 1 {
        return Err(
          "text watermark cannot fit even at font_size=1: needs \{need_w}x\{need_h}, \{avail_w}x\{avail_h} available at (\{cfg.x}, \{cfg.y})",
        )
      }
      wm = render_text_by_font(cfg.text, cfg.color, cfg.font, s)
    }
  }
  if cfg.angle != 0.0 {
    wm = wm.rotate(cfg.angle)
  }
  let alpha = clamp_opacity(cfg.opacity)
  if alpha == 0 {
    return Ok(self)
  }
  overlay_at(self, wm, cfg.x, cfg.y, alpha)
  Ok(self)
}

///|
/// 将 0.0~1.0 的不透明度转换为 0~255,越界值钳制。
fn clamp_opacity(opacity : Double) -> Int32 {
  let v = (opacity * 255.0).to_int()
  if v < 0 {
    0
  } else if v > 255 {
    255
  } else {
    v
  }
}