/// Bounded four-block AV1 reconstruction for a 64x64 luma plane.
///
/// This module assembles the four 32x32 children produced by a `SPLIT`
/// partition. Coefficient arrays are already dequantised integer transform
/// samples; entropy decoding remains in `av1_coeff_decode.mbt`. Chroma uses
/// four 16x16 children (4:2:0) and may be supplied as empty arrays for a
/// neutral 128 plane. The walker keeps prediction edges in raster order so
/// each child can reference reconstructed neighbours.

///|
/// copy one reconstructed block into a plane, adding intra prediction.
fn av1_reconstruct_child(
  plane : Array[Int],
  frame_width : Int,
  frame_height : Int,
  child : Av1SbBlock,
  mode : Int,
  coeffs : Array[Int],
  side : Int,
) -> Bool {
  av1_reconstruct_child_with_type(
    plane,
    frame_width,
    frame_height,
    child,
    mode,
    coeffs,
    side,
    Av1TxDctDct,
  )
}

///|
fn av1_reconstruct_child_with_type(
  plane : Array[Int],
  frame_width : Int,
  frame_height : Int,
  child : Av1SbBlock,
  mode : Int,
  coeffs : Array[Int],
  side : Int,
  tx_type : Av1TxType,
  bit_depth? : Int = 8,
) -> Bool {
  if child.width != side ||
    child.height != side ||
    child.row + side > frame_height ||
    child.col + side > frame_width {
    return false
  }
  let above : Array[Int] = []
  let left : Array[Int] = []
  let have_above = child.row > 0
  let have_left = child.col > 0
  if have_above {
    for j in 0.. value
    None => return false
  }
  let residual = match
    av1_reconstruct_block_with_type(coeffs, side, side, tx_type, bit_depth) {
    Some(value) => value
    None => return false
  }
  for y in 0.. hi { hi } else { value }
    }
  }
  true
}

///|
/// Reconstruct a rectangular transform leaf in raster order.
///
/// This path consumes both rectangular transform dimensions. The separate
/// square-transform helper requires width and height to match its side.
fn av1_reconstruct_rect_leaf_with_type(
  plane : Array[Int],
  frame_width : Int,
  frame_height : Int,
  leaf : Av1TxLeaf,
  mode : Int,
  coeffs : Array[Int],
  tx_type : Av1TxType,
  bit_depth : Int,
) -> Bool {
  let row = leaf.node.row
  let col = leaf.node.col
  let width = leaf.node.width
  let height = leaf.node.height
  if row < 0 ||
    col < 0 ||
    width <= 0 ||
    height <= 0 ||
    row + height > frame_height ||
    col + width > frame_width ||
    coeffs.length() != width * height {
    return false
  }
  let above : Array[Int] = []
  let left : Array[Int] = []
  let have_above = row > 0
  let have_left = col > 0
  if have_above {
    for x in 0.. value
    None => return false
  }
  let residual = match
    av1_reconstruct_block_with_type(coeffs, width, height, tx_type, bit_depth) {
    Some(value) => value
    None => return false
  }
  let hi = (1 << bit_depth) - 1
  for y in 0.. hi { hi } else { value }
    }
  }
  true
}

///|
/// Reconstruct luma from raster-ordered transform leaves.
pub fn av1_reconstruct_tx_luma(
  width : Int,
  height : Int,
  leaves : Array[Av1TxLeaf],
  coefficients : Array[Array[Int]],
  mode : Int,
  types : Array[Av1TxType],
  bit_depth? : Int = 8,
) -> Array[Int]? {
  if width <= 0 ||
    height <= 0 ||
    leaves.length() == 0 ||
    leaves.length() != coefficients.length() ||
    leaves.length() != types.length() {
    return None
  }
  let plane : Array[Int] = Array::make(width * height, 1 << (bit_depth - 1))
  for i in 0.. height || leaf.col + leaf.width > width {
      return None
    }
    if leaf.width == leaf.height {
      let child : Av1SbBlock = {
        row: leaf.row,
        col: leaf.col,
        width: leaf.width,
        height: leaf.height,
      }
      if !av1_reconstruct_child_with_type(
          plane,
          width,
          height,
          child,
          mode,
          coefficients[i],
          leaf.width,
          types[i],
          bit_depth~,
        ) {
        return None
      }
    } else if !av1_reconstruct_rect_leaf_with_type(
        plane,
        width,
        height,
        leaves[i],
        mode,
        coefficients[i],
        types[i],
        bit_depth,
      ) {
      return None
    }
  }
  Some(plane)
}

///|
/// Reconstruct one 4:2:0 chroma plane from 16×16 transform leaves.
pub fn av1_reconstruct_tx_chroma(
  leaves : Array[Av1TxLeaf],
  coefficients : Array[Array[Int]],
  mode : Int,
  types : Array[Av1TxType],
  size? : Int = 32,
  bit_depth? : Int = 8,
) -> Array[Int]? {
  av1_reconstruct_tx_luma(
    size,
    size,
    leaves,
    coefficients,
    mode,
    types,
    bit_depth~,
  )
}

///|
fn av1_reconstruct_tx_chroma_rect(
  width : Int,
  height : Int,
  leaves : Array[Av1TxLeaf],
  coefficients : Array[Array[Int]],
  mode : Int,
  types : Array[Av1TxType],
  bit_depth : Int,
) -> Array[Int]? {
  av1_reconstruct_tx_luma(
    width,
    height,
    leaves,
    coefficients,
    mode,
    types,
    bit_depth~,
  )
}

///|
/// Compose typed transform leaves for Y/U/V into an RGBA image.
pub fn av1_reconstruct_tx_rgba(
  width : Int,
  height : Int,
  y_leaves : Array[Av1TxLeaf],
  y_coefficients : Array[Array[Int]],
  u_leaves : Array[Av1TxLeaf],
  u_coefficients : Array[Array[Int]],
  v_leaves : Array[Av1TxLeaf],
  v_coefficients : Array[Array[Int]],
  y_mode : Int,
  uv_mode : Int,
  y_types : Array[Av1TxType],
  u_types : Array[Av1TxType],
  v_types : Array[Av1TxType],
  bit_depth : Int,
  full_range? : Bool = false,
  matrix_coefficients? : Int = 6,
) -> Image? {
  if (width != height && !av1_tx_rect_supported(width, height)) ||
    (width != 32 && width != 64 && width != 16) ||
    (bit_depth != 8 && bit_depth != 10 && bit_depth != 12) {
    return None
  }
  let y = match
    av1_reconstruct_tx_luma(
      width,
      height,
      y_leaves,
      y_coefficients,
      y_mode,
      y_types,
      bit_depth~,
    ) {
    Some(value) => value
    None => return None
  }
  let cw = (width + 1) / 2
  let ch = (height + 1) / 2
  let u = match
    av1_reconstruct_tx_chroma_rect(
      cw, ch, u_leaves, u_coefficients, uv_mode, u_types, bit_depth,
    ) {
    Some(value) => value
    None => return None
  }
  let v = match
    av1_reconstruct_tx_chroma_rect(
      cw, ch, v_leaves, v_coefficients, uv_mode, v_types, bit_depth,
    ) {
    Some(value) => value
    None => return None
  }
  av1_yuv420_highbd_to_rgba(
    width,
    height,
    y,
    u,
    v,
    bit_depth,
    full_range~,
    matrix_coefficients~,
  )
}

///|
/// convert an integer plane to bytes without allocating per sample.
fn av1_plane_bytes(values : Array[Int]) -> Array[Byte] {
  let out : Array[Byte] = []
  for value in values {
    out.push(clamp_byte(value))
  }
  out
}

///|
/// four-way 64x64 split reconstruction returning planar 8-bit YUV420.
///
/// `y_coeffs` contains four 32x32 dequantised coefficient blocks in the order
/// returned by `av1_partition_children(SPLIT)`. U and V contain four 16x16
/// blocks; an empty array means that the corresponding chroma plane is neutral.
/// Modes are intra mode numbers (DC/V/H/PAETH/SMOOTH variants). This bounded
/// path rejects non-four-way geometry and malformed block lengths.
pub fn av1_reconstruct_split_yuv420(
  y_coeffs : Array[Array[Int]],
  u_coeffs : Array[Array[Int]],
  v_coeffs : Array[Array[Int]],
  y_modes : Array[Int],
  u_modes : Array[Int],
  v_modes : Array[Int],
) -> (Array[Byte], Array[Byte], Array[Byte])? {
  if y_coeffs.length() != 4 ||
    y_modes.length() != 4 ||
    (u_coeffs.length() != 0 && u_coeffs.length() != 4) ||
    (v_coeffs.length() != 0 && v_coeffs.length() != 4) ||
    (u_coeffs.length() == 4 && u_modes.length() != 4) ||
    (v_coeffs.length() == 4 && v_modes.length() != 4) {
    return None
  }
  let root = av1_partition_node(0, 0, 64, 64, 64)
  let children = av1_partition_children(root, Av1SbPartitionSplit)
  if children.length() != 4 {
    return None
  }
  let y_plane : Array[Int] = Array::make(64 * 64, 128)
  for i in 0..<4 {
    if !av1_reconstruct_child(
        y_plane,
        64,
        64,
        children[i],
        y_modes[i],
        y_coeffs[i],
        32,
      ) {
      return None
    }
  }
  let chroma_children : Array[Av1SbBlock] = []
  for child in children {
    chroma_children.push({
      row: child.row / 2,
      col: child.col / 2,
      width: 16,
      height: 16,
    })
  }
  let u_plane : Array[Int] = Array::make(32 * 32, 128)
  let v_plane : Array[Int] = Array::make(32 * 32, 128)
  if u_coeffs.length() == 4 {
    for i in 0..<4 {
      if !av1_reconstruct_child(
          u_plane,
          32,
          32,
          chroma_children[i],
          u_modes[i],
          u_coeffs[i],
          16,
        ) {
        return None
      }
    }
  }
  if v_coeffs.length() == 4 {
    for i in 0..<4 {
      if !av1_reconstruct_child(
          v_plane,
          32,
          32,
          chroma_children[i],
          v_modes[i],
          v_coeffs[i],
          16,
        ) {
        return None
      }
    }
  }
  Some(
    (
      av1_plane_bytes(y_plane),
      av1_plane_bytes(u_plane),
      av1_plane_bytes(v_plane),
    ),
  )
}

///|
/// reconstruct a 64x64 RGBA image from four split luma children.
pub fn av1_reconstruct_split_64x64(
  y_coeffs : Array[Array[Int]],
  u_coeffs : Array[Array[Int]],
  v_coeffs : Array[Array[Int]],
  y_modes : Array[Int],
  u_modes : Array[Int],
  v_modes : Array[Int],
  full_range? : Bool = false,
  matrix_coefficients? : Int = 6,
) -> Image? {
  let (y, u, v) = match
    av1_reconstruct_split_yuv420(
      y_coeffs, u_coeffs, v_coeffs, y_modes, u_modes, v_modes,
    ) {
    Some(value) => value
    None => return None
  }
  av1_yuv420_to_rgba_color(64, 64, y, u, v, full_range~, matrix_coefficients~)
}

///|
/// zero-residual split produces a neutral 64x64 frame in full-range mode.
test "split reconstruction walks four children in raster order" {
  let block = Array::make(32 * 32, 0)
  let blocks : Array[Array[Int]] = [
    block.copy(),
    block.copy(),
    block.copy(),
    block.copy(),
  ]
  let (y, u, v) = av1_reconstruct_split_yuv420(
    blocks,
    [],
    [],
    [AV1_INTRA_DC, AV1_INTRA_DC, AV1_INTRA_DC, AV1_INTRA_DC],
    [],
    [],
  ).unwrap()
  assert_eq(y.length(), 4096)
  assert_eq(u.length(), 1024)
  assert_eq(v.length(), 1024)
  assert_eq(y[0].to_int(), 128)
  assert_eq(y[63].to_int(), 128)
  assert_eq(y[4095].to_int(), 128)
}

///|
/// malformed child arrays are rejected before transform allocation.
test "split reconstruction rejects malformed child blocks" {
  let block = Array::make(32 * 32, 0)
  assert_eq(
    av1_reconstruct_split_yuv420(
      [block.copy(), block.copy(), block.copy(), Array::make(3, 0)],
      [],
      [],
      [0, 0, 0, 0],
      [],
      [],
    ),
    None,
  )
}

///|
/// Reconstruct a four-way 4:2:0 split while carrying transform types per
/// plane and child. This is the typed counterpart to the legacy DCT_DCT API.
pub fn av1_reconstruct_split_yuv420_with_types(
  y_coeffs : Array[Array[Int]],
  u_coeffs : Array[Array[Int]],
  v_coeffs : Array[Array[Int]],
  y_modes : Array[Int],
  u_modes : Array[Int],
  v_modes : Array[Int],
  y_types : Array[Av1TxType],
  u_types : Array[Av1TxType],
  v_types : Array[Av1TxType],
) -> (Array[Byte], Array[Byte], Array[Byte])? {
  if y_coeffs.length() != 4 || y_modes.length() != 4 || y_types.length() != 4 {
    return None
  }
  let root = av1_partition_node(0, 0, 64, 64, 64)
  let children = av1_partition_children(root, Av1SbPartitionSplit)
  let y_plane : Array[Int] = Array::make(64 * 64, 128)
  for i in 0..<4 {
    if !av1_reconstruct_child_with_type(
        y_plane,
        64,
        64,
        children[i],
        y_modes[i],
        y_coeffs[i],
        32,
        y_types[i],
      ) {
      return None
    }
  }
  let u_plane : Array[Int] = Array::make(32 * 32, 128)
  let v_plane : Array[Int] = Array::make(32 * 32, 128)
  let chroma_children : Array[Av1SbBlock] = []
  for child in children {
    chroma_children.push({
      row: child.row / 2,
      col: child.col / 2,
      width: 16,
      height: 16,
    })
  }
  if u_coeffs.length() == 4 {
    if u_modes.length() != 4 || u_types.length() != 4 {
      return None
    }
    for i in 0..<4 {
      if !av1_reconstruct_child_with_type(
          u_plane,
          32,
          32,
          chroma_children[i],
          u_modes[i],
          u_coeffs[i],
          16,
          u_types[i],
        ) {
        return None
      }
    }
  }
  if v_coeffs.length() == 4 {
    if v_modes.length() != 4 || v_types.length() != 4 {
      return None
    }
    for i in 0..<4 {
      if !av1_reconstruct_child_with_type(
          v_plane,
          32,
          32,
          chroma_children[i],
          v_modes[i],
          v_coeffs[i],
          16,
          v_types[i],
        ) {
        return None
      }
    }
  }
  Some(
    (
      av1_plane_bytes(y_plane),
      av1_plane_bytes(u_plane),
      av1_plane_bytes(v_plane),
    ),
  )
}

///|
fn av1_reconstruct_block_with_type(
  coeffs : Array[Int],
  width : Int,
  height : Int,
  tx_type : Av1TxType,
  bit_depth : Int,
) -> Array[Int]? {
  if coeffs.length() != width * height {
    return None
  }
  av1_inverse_transform_2d(tx_type, coeffs, width, height, bit_depth)
}

///|
test "split reconstruction accepts non-DC chroma modes" {
  let y = Array::make(32 * 32, 0)
  let c = Array::make(16 * 16, 0)
  let out = av1_reconstruct_split_yuv420(
    [y.copy(), y.copy(), y.copy(), y.copy()],
    [c.copy(), c.copy(), c.copy(), c.copy()],
    [c.copy(), c.copy(), c.copy(), c.copy()],
    [AV1_INTRA_DC, AV1_INTRA_DC, AV1_INTRA_DC, AV1_INTRA_DC],
    [AV1_INTRA_V, AV1_INTRA_H, AV1_INTRA_PAETH, AV1_INTRA_DC],
    [AV1_INTRA_H, AV1_INTRA_V, AV1_INTRA_PAETH, AV1_INTRA_DC],
  )
  assert_true(out is Some(_))
}

///|
test "block reconstruction dispatches a four-point ADST" {
  let values = Array::make(16, 0)
  values[0] = 100
  let out = av1_reconstruct_block_with_type(values, 4, 4, Av1TxAdstAdst, 8).unwrap()
  assert_eq(out.length(), 16)
}

///|
test "typed split reconstruction carries per-plane transform types" {
  let y = Array::make(32 * 32, 0)
  let c = Array::make(16 * 16, 0)
  let result = av1_reconstruct_split_yuv420_with_types(
    [y.copy(), y.copy(), y.copy(), y.copy()],
    [c.copy(), c.copy(), c.copy(), c.copy()],
    [c.copy(), c.copy(), c.copy(), c.copy()],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [Av1TxDctDct, Av1TxDctDct, Av1TxDctDct, Av1TxDctDct],
    [Av1TxAdstAdst, Av1TxDctDct, Av1TxDctDct, Av1TxDctDct],
    [Av1TxDctDct, Av1TxDctDct, Av1TxDctDct, Av1TxDctDct],
  )
  assert_true(result is Some(_))
}

///|
test "tx luma assembler places raster leaves" {
  let leaves : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 16, height: 16, }, depth: 1, },
    { node: { row: 0, col: 16, width: 16, height: 16, }, depth: 1, },
    { node: { row: 16, col: 0, width: 16, height: 16, }, depth: 1, },
    { node: { row: 16, col: 16, width: 16, height: 16, }, depth: 1, },
  ]
  let coeff = Array::make(16 * 16, 0)
  let plane = av1_reconstruct_tx_luma(
    32,
    32,
    leaves,
    [coeff.copy(), coeff.copy(), coeff.copy(), coeff.copy()],
    AV1_INTRA_DC,
    [Av1TxDctDct, Av1TxDctDct, Av1TxDctDct, Av1TxDctDct],
  ).unwrap()
  assert_eq(plane.length(), 1024)
  assert_eq(plane[0], 128)
}

///|
test "tx luma assembler accepts rectangular transform leaves" {
  let leaf : Av1TxLeaf = {
    node: { row: 0, col: 0, width: 8, height: 4, },
    depth: 0,
  }
  let coeff = Array::make(8 * 4, 0)
  let plane = av1_reconstruct_tx_luma(8, 4, [leaf], [coeff], AV1_INTRA_DC, [
    Av1TxDctDct,
  ]).unwrap()
  assert_eq(plane.length(), 32)
  assert_eq(plane[0], 128)
}

///|
test "tx luma assembler reconstructs both 32x16 orientations" {
  let a : Av1TxLeaf = {
    node: { row: 0, col: 0, width: 32, height: 16, },
    depth: 0,
  }
  let b : Av1TxLeaf = {
    node: { row: 0, col: 0, width: 16, height: 32, },
    depth: 0,
  }
  let ca = Array::make(32 * 16, 0)
  let cb = Array::make(16 * 32, 0)
  ca[0] = 8
  cb[0] = 8
  assert_true(
    av1_reconstruct_tx_luma(32, 16, [a], [ca], AV1_INTRA_DC, [Av1TxDctDct])
    is Some(_),
  )
  assert_true(
    av1_reconstruct_tx_luma(16, 32, [b], [cb], AV1_INTRA_DC, [Av1TxDctDct])
    is Some(_),
  )
}

///|
/// Large rectangular transforms use the same raster leaf assembler; their
/// coefficient decoder supplies the full 64x32/32x64 plane shape.
test "tx luma assembler reconstructs 64x32 and 32x64" {
  let a : Av1TxLeaf = {
    node: { row: 0, col: 0, width: 64, height: 32, },
    depth: 0,
  }
  let b : Av1TxLeaf = {
    node: { row: 0, col: 0, width: 32, height: 64, },
    depth: 0,
  }
  let ca = Array::make(64 * 32, 0)
  let cb = Array::make(32 * 64, 0)
  assert_true(
    av1_reconstruct_tx_luma(64, 32, [a], [ca], AV1_INTRA_DC, [Av1TxDctDct])
    is Some(_),
  )
  assert_true(
    av1_reconstruct_tx_luma(32, 64, [b], [cb], AV1_INTRA_DC, [Av1TxDctDct])
    is Some(_),
  )
}

///|
test "tx chroma assembler uses 16 pixel leaves" {
  let leaves : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 16, height: 16, }, depth: 1, },
    { node: { row: 0, col: 16, width: 16, height: 16, }, depth: 1, },
    { node: { row: 16, col: 0, width: 16, height: 16, }, depth: 1, },
    { node: { row: 16, col: 16, width: 16, height: 16, }, depth: 1, },
  ]
  let coeff = Array::make(16 * 16, 0)
  let plane = av1_reconstruct_tx_chroma(
    leaves,
    [coeff.copy(), coeff.copy(), coeff.copy(), coeff.copy()],
    AV1_INTRA_DC,
    [Av1TxDctDct, Av1TxDctDct, Av1TxDctDct, Av1TxDctDct],
  ).unwrap()
  assert_eq(plane.length(), 1024)
  assert_eq(plane[1023], 128)
}

///|
test "typed transform planes compose through the highbd RGBA path" {
  let y_leaf : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 32, height: 32, }, depth: 0, },
  ]
  let c_leaf : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 16, height: 16, }, depth: 0, },
  ]
  let y = Array::make(32 * 32, 0)
  let c = Array::make(16 * 16, 0)
  let image = av1_reconstruct_tx_rgba(
    32,
    32,
    y_leaf,
    [y],
    c_leaf,
    [c.copy()],
    c_leaf,
    [c.copy()],
    AV1_INTRA_DC,
    AV1_INTRA_DC,
    [Av1TxDctDct],
    [Av1TxDctDct],
    [Av1TxDctDct],
    10,
  ).unwrap()
  assert_eq(image.get_pixel(0, 0).3, b'\xFF')
}

///|
test "typed transform planes compose rectangular 420 geometry" {
  let y_leaf : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 32, height: 16, }, depth: 0, },
  ]
  let c_leaf : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 16, height: 8, }, depth: 0, },
  ]
  let y = Array::make(32 * 16, 0)
  let c = Array::make(16 * 8, 0)
  let image = av1_reconstruct_tx_rgba(
    32,
    16,
    y_leaf,
    [y],
    c_leaf,
    [c.copy()],
    c_leaf,
    [c.copy()],
    AV1_INTRA_DC,
    AV1_INTRA_DC,
    [Av1TxDctDct],
    [Av1TxDctDct],
    [Av1TxDctDct],
    8,
  ).unwrap()
  assert_eq(image.width, 32)
  assert_eq(image.height, 16)
  assert_eq(image.get_pixel(31, 15).3, b'\xFF')
}

///|
/// The large rectangular entry carries the 4:2:0 plane geometry through the
/// same typed reconstruction path (64x32 luma -> 32x16 chroma).
test "typed transform planes compose 64x32 rectangular geometry" {
  let y_leaf : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 64, height: 32, }, depth: 0, },
  ]
  let c_leaf : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 32, height: 16, }, depth: 0, },
  ]
  let y = Array::make(64 * 32, 0)
  let c = Array::make(32 * 16, 0)
  let image = av1_reconstruct_tx_rgba(
    64,
    32,
    y_leaf,
    [y],
    c_leaf,
    [c.copy()],
    c_leaf,
    [c.copy()],
    AV1_INTRA_DC,
    AV1_INTRA_DC,
    [Av1TxDctDct],
    [Av1TxDctDct],
    [Av1TxDctDct],
    8,
  ).unwrap()
  assert_eq((image.width, image.height), (64, 32))
  assert_eq(image.get_pixel(63, 31).3, b'\xFF')
}

///|
/// The transposed 16x64 form maps to an 8x32 4:2:0 chroma plane.
test "typed transform planes compose 16x64 rectangular geometry" {
  let y_leaf : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 16, height: 64, }, depth: 0, },
  ]
  let c_leaf : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 8, height: 32, }, depth: 0, },
  ]
  let y = Array::make(16 * 64, 0)
  let c = Array::make(8 * 32, 0)
  let image = av1_reconstruct_tx_rgba(
    16,
    64,
    y_leaf,
    [y],
    c_leaf,
    [c.copy()],
    c_leaf,
    [c.copy()],
    AV1_INTRA_DC,
    AV1_INTRA_DC,
    [Av1TxDctDct],
    [Av1TxDctDct],
    [Av1TxDctDct],
    8,
  ).unwrap()
  assert_eq((image.width, image.height), (16, 64))
  assert_eq(image.get_pixel(15, 63).3, b'\xFF')
}

///|
test "typed transform planes compose at 12-bit precision" {
  let y_leaf : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 32, height: 32, }, depth: 0, },
  ]
  let c_leaf : Array[Av1TxLeaf] = [
    { node: { row: 0, col: 0, width: 16, height: 16, }, depth: 0, },
  ]
  let y = Array::make(32 * 32, 0)
  let c = Array::make(16 * 16, 0)
  let image = av1_reconstruct_tx_rgba(
    32,
    32,
    y_leaf,
    [y],
    c_leaf,
    [c.copy()],
    c_leaf,
    [c.copy()],
    AV1_INTRA_DC,
    AV1_INTRA_DC,
    [Av1TxDctDct],
    [Av1TxDctDct],
    [Av1TxDctDct],
    12,
  ).unwrap()
  assert_eq(image.get_pixel(0, 0).3, b'\xFF')
}