///|
/// DCT 域不可见水印:8×8 分块 DCT-II,中频系数 QIM(量化索引调制)嵌入。
///
/// 与 LSB 的取舍:LSB 抗无损但被 JPEG 量化破坏;DCT 域将 bit 编码进
/// 中频 DCT 系数的量化网格,JPEG 重压后系数仍在网格内即可提取——
/// 实测 JPEG q60 往返可提取(见 `dct_wbtest.mbt`)。
///
/// 布局(逐块 1 bit,按行主序):[magic 2B "MD"] [len 2B] [payload]。
/// 嵌入系数固定为 (u=4, v=1)(中频、JPEG 量化步长适中);量化步长
/// `delta` 默认 24,越大越鲁棒、可见性略升。

///|
/// 将 `payload` 以 DCT 域方式嵌入(原地修改)。容量 = 完整 8×8 块数 / 8 字节。
pub fn RgbaImage::embed_dct(
  self : RgbaImage,
  payload : Bytes,
  delta? : Int,
) -> Result[RgbaImage, String] {
  let d = match delta {
    Some(v) => v
    None => 24
  }
  let blocks = self.width / 8 * (self.height / 8)
  let need = 4 + payload.length()
  if need * 8 > blocks {
    return Err("payload too large: \{need}B > \{blocks / 8}B capacity")
  }
  // 明文帧:magic + len + payload
  let frame = FixedArray::make(need, (0).to_byte())
  frame[0] = b'M'
  frame[1] = b'D'
  frame[2] = ((payload.length() >> 8) & 0xFF).to_byte()
  frame[3] = (payload.length() & 0xFF).to_byte()
  for i in 0..= need * 8 {
        break
      }
      let bit = (frame[bi / 8].to_int() >> (bi % 8)) & 1
      self.embed_dct_bit(bx * 8, by * 8, bit, d)
      bi += 1
    }
  }
  Ok(self)
}

///|
/// 从图像提取 DCT 域水印;magic 校验失败返回 `None`。
pub fn extract_dct(img : RgbaImage, delta? : Int) -> Bytes? {
  let d = match delta {
    Some(v) => v
    None => 24
  }
  let blocks = img.width / 8 * (img.height / 8)
  if blocks < 32 {
    return None // 至少 4 字节头部
  }
  let head = FixedArray::make(4, (0).to_byte())
  for bi in 0..<32 {
    let bx = bi % (img.width / 8)
    let by = bi / (img.width / 8)
    head[bi / 8] = (head[bi / 8].to_int() |
    (extract_dct_bit(img, bx * 8, by * 8, d) << (bi % 8))).to_byte()
  }
  if head[0] != b'M' || head[1] != b'D' {
    return None
  }
  let len = (head[2].to_int() << 8) | head[3].to_int()
  let need = 4 + len
  if need * 8 > blocks {
    return None
  }
  let frame = FixedArray::make(need, (0).to_byte())
  for i in 0..<4 {
    frame[i] = head[i]
  }
  for bi in 32..<(need * 8) {
    let bx = bi % (img.width / 8)
    let by = bi / (img.width / 8)
    frame[bi / 8] = (frame[bi / 8].to_int() |
    (extract_dct_bit(img, bx * 8, by * 8, d) << (bi % 8))).to_byte()
  }
  let out = Array::make(len, (0).to_byte())
  for i in 0.. Unit {
  // 取 G 通道到块矩阵(独立行,避免嵌套 make 共享引用)
  let f = dct8()
  for n in 0..<8 {
    for m in 0..<8 {
      let p = self.get_pixel(x0 + m, y0 + n)
      f[n][m] = ((p >> 16) & 0xFF).to_double()
    }
  }
  let fk = dct_2d(f)
  // QIM:目标网格奇偶 = bit(偶=0,奇=1);与原始网格至多差 1 格
  let q0 = (fk[4][1] / delta.to_double()).round().to_int()
  let tq = if bit == 1 { q0 | 1 } else { q0 & -2 }
  fk[4][1] = tq.to_double() * delta.to_double()
  let back = idct_2d(fk)
  for n in 0..<8 {
    for m in 0..<8 {
      // clamp 到 [0,255](不跳过:跳过会破坏块的 DCT 域完整性)
      let g = back[n][m].round()
      let gv = if g < 0.0 { 0.0 } else if g > 255.0 { 255.0 } else { g }
      let p = self.get_pixel(x0 + m, y0 + n)
      let np = (p & 0xFF00_FFFF) | ((gv.to_int() & 0xFF) << 16)
      self.set_pixel(x0 + m, y0 + n, np)
    }
  }
}

///|
/// 提取 1 bit:系数网格奇偶判定。
fn extract_dct_bit(img : RgbaImage, x0 : Int, y0 : Int, delta : Int) -> Int {
  let f = dct8()
  for n in 0..<8 {
    for m in 0..<8 {
      let p = img.get_pixel(x0 + m, y0 + n)
      f[n][m] = ((p >> 16) & 0xFF).to_double()
    }
  }
  let fk = dct_2d(f)
  let q0 = (fk[4][1] / delta.to_double()).round().to_int()
  q0 & 1
}

///|
/// 构造 8×8 独立行矩阵(FixedArray/Array 嵌套 make 会共享引用,必须逐行新建)。
fn dct8() -> Array[FixedArray[Double]] {
  let rows = Array(capacity=8)
  for _ in 0..<8 {
    rows.push(FixedArray::make(8, 0.0))
  }
  rows
}

///|
/// 8×8 DCT-II 正变换。
fn dct_2d(f : Array[FixedArray[Double]]) -> Array[FixedArray[Double]] {
  let out = dct8()
  for u in 0..<8 {
    for v in 0..<8 {
      let mut s = 0.0
      for n in 0..<8 {
        for m in 0..<8 {
          s = s + f[n][m] * cos_t(u, n) * cos_t(v, m)
        }
      }
      out[u][v] = 0.25 * dct_alpha(u) * dct_alpha(v) * s
    }
  }
  out
}

///|
/// 8×8 DCT-II 逆变换。
fn idct_2d(fk : Array[FixedArray[Double]]) -> Array[FixedArray[Double]] {
  let out = dct8()
  for n in 0..<8 {
    for m in 0..<8 {
      let mut s = 0.0
      for u in 0..<8 {
        for v in 0..<8 {
          s = s +
            dct_alpha(u) * dct_alpha(v) * fk[u][v] * cos_t(u, n) * cos_t(v, m)
        }
      }
      out[n][m] = 0.25 * s
    }
  }
  out
}

///|
/// DCT 基函数:cos(π(2n+1)u/16)。
fn cos_t(u : Int, n : Int) -> Double {
  @math.cos(3.141592653589793 * ((2 * n + 1) * u).to_double() / 16.0)
}

///|
/// 归一化因子:u=0 时 1/√2,否则 1。
fn dct_alpha(u : Int) -> Double {
  if u == 0 {
    1.0 / 1.4142135623730951
  } else {
    1.0
  }
}