///|
/// moon-watermark 命令行入口。
///
/// 两种模式:
///  1. 无参数:内存闭环演示(生成渐变图 → 水印 → PNG 往返 → 提取验证);
///  2. 文件模式:对真实图片文件嵌入 / 验证水印。
///
/// 用法:
///  ```
///  # 嵌入(默认文本水印 + 点阵溯源水印)
///  moon run cmd/main -- embed in.png out.png --text "LIVE 2026-10-03" --font cjk16
///  # 追加不可见水印(LSB,携带 ID)
///  moon run cmd/main -- embed in.jpg out.jpg --text "防搬运" --font cjk16 --lsb "UID-001" --key 42
///  # DCT 域水印(抗 JPEG 重压)
///  moon run cmd/main -- embed in.png out.png --dct "UID-001"
///  # 平铺水印(防盗摄全幅覆盖)
///  moon run cmd/main -- embed in.png out.png --tiled "请勿转载" --font cjk16
///  # 提取验证
///  moon run cmd/main -- verify-dots in.png --seed 42
///  moon run cmd/main -- verify-lsb in.png --key 42
///  moon run cmd/main -- verify-dct in.png
///  ```
///  输入输出格式由扩展名决定(.png / .jpg / .jpeg);JPEG 输出默认质量 85。
fn main {
  let args = @env.args()
  if args.length() <= 1 {
    demo()
    return
  }
  match args[1] {
    "embed" => cmd_embed(args)
    "verify-dots" => cmd_verify_dots(args)
    "verify-lsb" => cmd_verify_lsb(args)
    "verify-dct" => cmd_verify_dct(args)
    _ =>
      println(
        "usage: moon run cmd/main -- embed   [--text T --font ascii5x7|cjk16 --opacity N --seed N --lsb PAYLOAD --key N --dct PAYLOAD --tiled T] | verify-dots  [--seed N --density D --dot-size N] | verify-lsb  [--key N] | verify-dct ",
      )
  }
}

///|
/// 内存闭环演示(无文件 IO)。
fn demo() -> Unit {
  let img = @lib.RgbaImage::new(320, 240, 0xFFFF_FFFF)
  for y in 0..<240 {
    for x in 0..<320 {
      let r = x * 255 / 319
      let g = y * 255 / 239
      img.set_pixel(x, y, (r << 16) | (g << 8) | 255)
    }
  }
  println("created 320x240 test image")
  // 可见水印 embed_* 统一返回 Result(当前无失败路径,Ok 恒成立)
  let tcfg = @lib.TextConfig::new("LIVE", 8, 8, 2, 0.6, 0xFF00_00FF)
  let _ = img.embed_text(tcfg)
  println("embedded text watermark")
  let dcfg = @lib.DotConfig::default()
  let _ = img.embed_dots(dcfg)
  println("embedded dot watermark (seed=\{dcfg.seed})")
  let png = img.encode_png()
  match png {
    Ok(bytes) => {
      println("encoded png: \{bytes.length()} bytes")
      match @lib.decode_png(bytes) {
        Ok(back) => {
          let rate = @lib.extract_dots(back, dcfg)
          println("dot extraction hit rate: \{rate}")
          let ok = rate >= 0.9
          println("verification: \{if ok { "PASS" } else { "FAIL" }}")
        }
        Err(e) => println("decode failed: \{e}")
      }
    }
    Err(e) => println("encode failed: \{e}")
  }
}

///|
/// 解析整数参数;失败时返回默认值。
fn parse_int_or(s : String, d : Int32) -> Int32 {
  @string.parse_int(s.to_string_view()) catch {
    _ => d
  }
}

///|
/// 解析浮点参数;失败时返回默认值。
fn parse_double_or(s : String, d : Double) -> Double {
  @string.parse_double(s.to_string_view()) catch {
    _ => d
  }
}

///|
/// 解析 64 位整数参数;失败时返回默认值。
fn parse_int64_or(s : String, d : Int64) -> Int64 {
  @string.parse_int64(s.to_string_view()) catch {
    _ => d
  }
}

///|
/// 从命令行参数取 flag 值(`--name value`)。
fn flag_value(args : Array[String], name : String) -> String? {
  for i in 0.. Bool {
  for i in 0.. Bool {
  path.has_suffix(".jpg") || path.has_suffix(".jpeg")
}

///|
/// 按扩展名读取并解码图片(PNG / JPEG)。
fn load_image(path : String) -> Result[@lib.RgbaImage, String] {
  try {
    let bytes = @fs.read_file_to_bytes(path)
    if path.has_suffix(".png") {
      @lib.decode_png(bytes)
    } else if is_jpeg(path) {
      @lib.decode_jpeg(bytes)
    } else {
      Err("unsupported input format: use .png / .jpg / .jpeg")
    }
  } catch {
    _ => Err("cannot read file: \{path}")
  }
}

///|
/// 按扩展名编码并写入图片(PNG / JPEG,质量默认 85)。
fn save_image(img : @lib.RgbaImage, path : String) -> Result[Unit, String] {
  let bytes = if path.has_suffix(".png") {
    img.encode_png()
  } else if is_jpeg(path) {
    img.encode_jpeg(85)
  } else {
    return Err("unsupported output format: use .png / .jpg / .jpeg")
  }
  match bytes {
    Ok(b) =>
      try {
        @fs.write_bytes_to_file(path, b)
        Ok(())
      } catch {
        _ => Err("cannot write file: \{path}")
      }
    Err(e) => Err(e)
  }
}

///|
/// 将命令行文本参数编码为 UTF-8 字节(`String::to_bytes` 是 UTF-16,不能直用)。
fn payload_bytes(s : String) -> Bytes {
  @utf8.encode(s.to_string_view())
}

///|
/// 逐字节打印 Bytes(规避 Bytes::to_string 的编码显示歧义)。
fn debug_bytes(b : Bytes) -> String {
  let parts = Array::make(0, "")
  for i in 0.. @lib.DotConfig {
  let seed = match flag_value(args, "--seed") {
    Some(v) => parse_int64_or(v, 42L)
    None => 42L
  }
  let density = match flag_value(args, "--density") {
    Some(v) => parse_double_or(v, 0.05)
    None => 0.05
  }
  let dot_size = match flag_value(args, "--dot-size") {
    Some(v) => parse_int_or(v, 3)
    None => 3
  }
  @lib.DotConfig::new(density, dot_size, seed, opacity, 0, 0)
}

///|
/// embed 子命令:读入图片 → 按 flag 嵌入水印 → 写出。
fn cmd_embed(args : Array[String]) -> Unit {
  if args.length() < 4 {
    println("usage: moon run cmd/main -- embed   [flags]")
    return
  }
  let inp = args[2]
  let outp = args[3]
  match load_image(inp) {
    Err(e) => println("error: \{e}")
    Ok(img) => {
      // 文本水印(默认 "LIVE" + 点阵;位置右下角,避开不可见水印的左上角头部区)
      let text = match flag_value(args, "--text") {
        Some(v) => v
        None => "LIVE"
      }
      let font = match flag_value(args, "--font") {
        Some(v) => v
        None => "ascii5x7"
      }
      // 未知字体静默降级会误导用户:显式警告后回退
      if font != "ascii5x7" && font != "cjk16" {
        println("warning: unknown font '\{font}', fallback to ascii5x7")
      }
      let font_ok = if font == "cjk16" { font } else { "ascii5x7" }
      let opacity = match flag_value(args, "--opacity") {
        Some(v) => parse_double_or(v, 0.6)
        None => 0.6
      }
      let cell_h = if font_ok == "cjk16" { 16 } else { 7 }
      let ty = img.height - 8 - 2 * cell_h
      let ty_ok = if ty < 0 { 0 } else { ty }
      // v0.1.11 起 embed_text 越界返回 Err:打印警告而不是静默失败
      match
        img.embed_text(
          @lib.TextConfig::with_font(
            text, 8, ty_ok, 2, opacity, 0xFF00_00FF, font_ok,
          ),
        ) {
        Ok(_) => ()
        Err(e) =>
          println(
            "warning: text embed failed: \{e} (consider --auto-shrink or shorter text)",
          )
      }
      // 点阵溯源水印(默认 seed 42;--no-dots 关闭;--opacity 同时作用于点阵)
      if !has_flag(args, "--no-dots") {
        let dcfg = dot_cfg_from_args(args, opacity)
        let _ = img.embed_dots(dcfg)
      }
      // 可选 LSB 不可见水印(与 DCT 互斥:DCT 重写 G 通道会破坏 LSB,先警告)
      let has_lsb = flag_value(args, "--lsb") is Some(_)
      let has_dct = flag_value(args, "--dct") is Some(_)
      if has_lsb && has_dct {
        println(
          "warning: LSB and DCT are mutually exclusive (DCT rewrites luma, destroying LSB) — DCT skipped, LSB kept",
        )
      }
      match flag_value(args, "--lsb") {
        Some(payload) => {
          let key = match flag_value(args, "--key") {
            Some(v) => parse_int64_or(v, 0L)
            None => 0L
          }
          match img.embed_invisible(payload_bytes(payload), key~) {
            Ok(_) => ()
            Err(e) => println("warning: LSB embed failed: \{e}")
          }
        }
        None => ()
      }
      // 可选 DCT 域水印(--delta 控制量化步长,默认 24;纹理图抗 JPEG 建议加大)
      match flag_value(args, "--dct") {
        Some(payload) if !has_lsb => {
          let delta = match flag_value(args, "--delta") {
            Some(v) => parse_int_or(v, 24)
            None => 24
          }
          match img.embed_dct(payload_bytes(payload), delta~) {
            Ok(_) => ()
            Err(e) => println("warning: DCT embed failed: \{e}")
          }
        }
        _ => ()
      }
      // 可选平铺水印
      match flag_value(args, "--tiled") {
        Some(ttext) => {
          let _ = img.embed_tiled(
            @lib.TiledConfig::new(ttext, 1, 40, 40, 0.25, 0xFF00_00FF, font~),
          )
        }
        None => ()
      }
      match save_image(img, outp) {
        Ok(_) => println("saved: \{outp} (from \{inp})")
        Err(e) => println("error: \{e}")
      }
    }
  }
}

///|
/// verify-dots 子命令:按配置计算点阵成对对照信号并判定。
/// 输出:绝对命中率(鲁棒性参考)+ contrast(判别信号,自动扣原图暗区干扰)。
fn cmd_verify_dots(args : Array[String]) -> Unit {
  if args.length() < 3 {
    println(
      "usage: moon run cmd/main -- verify-dots  [--seed N --density D --dot-size N]",
    )
    return
  }
  let inp = args[2]
  match load_image(inp) {
    Err(e) => println("error: \{e}")
    Ok(img) => {
      let cfg = dot_cfg_from_args(args, 1.0)
      let hit = @lib.extract_dots(img, cfg)
      let contrast = @lib.dot_contrast(img, cfg)
      let verdict = @lib.verify_dots(img, cfg)
      println(
        "dot hit rate: \{hit} | contrast: \{contrast} (threshold 0.5) verdict: \{if verdict { "PASS" } else { "FAIL" }}",
      )
    }
  }
}

///|
/// verify-lsb 子命令:提取 LSB 水印并打印 payload。
fn cmd_verify_lsb(args : Array[String]) -> Unit {
  if args.length() < 3 {
    println("usage: moon run cmd/main -- verify-lsb  [--key N]")
    return
  }
  let inp = args[2]
  match load_image(inp) {
    Err(e) => println("error: \{e}")
    Ok(img) => {
      let key = match flag_value(args, "--key") {
        Some(v) => parse_int64_or(v, 0L)
        None => 0L
      }
      match @lib.extract_invisible(img, key~) {
        Some(payload) => println("lsb payload bytes: \{debug_bytes(payload)}")
        None => println("lsb watermark not found (wrong key or absent)")
      }
    }
  }
}

///|
/// verify-dct 子命令:提取 DCT 水印并打印 payload。
fn cmd_verify_dct(args : Array[String]) -> Unit {
  if args.length() < 3 {
    println("usage: moon run cmd/main -- verify-dct  [--delta N]")
    return
  }
  let inp = args[2]
  match load_image(inp) {
    Err(e) => println("error: \{e}")
    Ok(img) => {
      let delta = match flag_value(args, "--delta") {
        Some(v) => parse_int_or(v, 24)
        None => 24
      }
      match @lib.extract_dct(img, delta~) {
        Some(payload) => println("dct payload bytes: \{debug_bytes(payload)}")
        None => println("dct watermark not found")
      }
    }
  }
}