///|
/// 组合嵌入:一次调用按 `EmbedOptions` 依次叠加可见水印(文本/点阵)与
/// 不可见水印(LSB 或 DCT)。把 CLI 的组合逻辑库化,供逐帧应用(如直播
/// 贴片)复用——构造一次 `EmbedOptions`,对每帧调用 `embed_all`。
///
/// 组合顺序与约束:
/// 1. 可见水印先嵌(文本 → 点阵),不可见水印最后(避免覆盖其头部区);
/// 2. **LSB 与 DCT 互斥**——DCT 重写亮度分量会破坏 LSB,同时指定返回
///    `Err`(与 CLI 的"保留 LSB 跳过 DCT"策略不同:库 API 不静默降级);
/// 3. 任一子嵌入失败(如 payload 超容量)立即返回 Err,不产生半成品。

///|
/// 一次组合嵌入的完整配置。未启用的通道置 `None`:
///
/// ```mbt nocheck
/// let opts = {
///   text_cfg: Some(tcfg),
///   lsb_payload: Some(payload),
///   lsb_key: 7L,
///   dot_cfg: None,
///   dct_payload: None,
///   dct_delta: 24,
/// }
/// ```
pub(all) struct EmbedOptions {
  text_cfg : TextConfig?
  dot_cfg : DotConfig?
  lsb_payload : Bytes?
  lsb_key : Int64? // None = 明文帧(无混淆,detect_lsb 可直接检出)
  dct_payload : Bytes?
  dct_delta : Int32
}

///|
/// 全通道关闭的默认配置(各字段含义见 [`EmbedOptions`])。
pub fn EmbedOptions::default() -> EmbedOptions {
  {
    text_cfg: None,
    dot_cfg: None,
    lsb_payload: None,
    lsb_key: None,
    dct_payload: None,
    dct_delta: 24,
  }
}

///|
/// 按配置组合嵌入水印并返回新图像(原图不变)。
pub fn RgbaImage::embed_all(
  self : RgbaImage,
  opts : EmbedOptions,
) -> Result[RgbaImage, String] {
  let mut img = self
  match opts.text_cfg {
    Some(c) =>
      match img.embed_text(c) {
        Ok(m) => img = m
        Err(e) => return Err(e)
      }
    None => ()
  }
  match opts.dot_cfg {
    Some(c) =>
      match img.embed_dots(c) {
        Ok(m) => img = m
        Err(e) => return Err(e)
      }
    None => ()
  }
  // LSB 与 DCT 互斥:DCT 重写亮度分量会破坏 LSB,库 API 明确报错而非静默降级
  if opts.lsb_payload is Some(_) && opts.dct_payload is Some(_) {
    return Err(
      "lsb and dct cannot be embedded together (dct rewrites luma, destroying lsb)",
    )
  }
  match opts.lsb_payload {
    Some(p) => {
      let r = match opts.lsb_key {
        Some(k) => img.embed_invisible(p, key=k)
        None => img.embed_invisible(p)
      }
      match r {
        Ok(m) => img = m
        Err(e) => return Err(e)
      }
    }
    None => ()
  }
  match opts.dct_payload {
    Some(p) =>
      match img.embed_dct(p, delta=opts.dct_delta) {
        Ok(m) => img = m
        Err(e) => return Err(e)
      }
    None => ()
  }
  Ok(img)
}