///|
fn clamp_int(v : Int, lo : Int, hi : Int) -> Int {
  if v < lo {
    lo
  } else if v > hi {
    hi
  } else {
    v
  }
}

///|
fn get_pixel(
  src : FixedArray[Byte],
  width : Int,
  height : Int,
  x : Int,
  y : Int,
) -> (Int, Int, Int, Int) {
  let cx = clamp_int(x, 0, width - 1)
  let cy = clamp_int(y, 0, height - 1)
  let idx = (cy * width + cx) * 4
  (
    src[idx].to_int(),
    src[idx + 1].to_int(),
    src[idx + 2].to_int(),
    src[idx + 3].to_int(),
  )
}

///|
fn clamp_to_byte(v : Double) -> Byte {
  if v < 0.0 {
    b'\x00'
  } else if v > 255.0 {
    b'\xFF'
  } else {
    v.to_int().to_byte()
  }
}

///|
fn cubic_weight(t : Double) -> Double {
  let a = -0.5
  let abs_t = if t < 0.0 { -t } else { t }
  if abs_t <= 1.0 {
    (a + 2.0) * abs_t * abs_t * abs_t - (a + 3.0) * abs_t * abs_t + 1.0
  } else if abs_t <= 2.0 {
    a * abs_t * abs_t * abs_t -
    5.0 * a * abs_t * abs_t +
    8.0 * a * abs_t -
    4.0 * a
  } else {
    0.0
  }
}

///|
fn resize_nearest(
  img : ImageData,
  new_width : Int,
  new_height : Int,
) -> ImageData {
  let src = img.data.to_fixedarray()
  let src_w = img.width
  let src_h = img.height
  let buf = FixedArray::make(new_width * new_height * 4, b'\x00')
  for dy in 0.. ImageData {
  let src = img.data.to_fixedarray()
  let src_w = img.width.to_double()
  let src_h = img.height.to_double()
  let dst_w = new_width.to_double()
  let dst_h = new_height.to_double()
  let buf = FixedArray::make(new_width * new_height * 4, b'\x00')
  for dy in 0.. ImageData {
  let src = img.data.to_fixedarray()
  let src_w = img.width.to_double()
  let src_h = img.height.to_double()
  let dst_w = new_width.to_double()
  let dst_h = new_height.to_double()
  let buf = FixedArray::make(new_width * new_height * 4, b'\x00')
  for dy in 0.. ImageData raise EncodeError {
  if new_width <= 0 || new_height <= 0 {
    raise InvalidDimensions(
      "width and height must be positive, got " +
      new_width.to_string() +
      "x" +
      new_height.to_string(),
    )
  }
  if new_width == img.width && new_height == img.height {
    let arr = img.data.to_fixedarray()
    return {
      width: img.width,
      height: img.height,
      data: Bytes::from_array(arr),
    }
  }
  match resize_method {
    Nearest => resize_nearest(img, new_width, new_height)
    Bilinear => resize_bilinear(img, new_width, new_height)
    Bicubic => resize_bicubic(img, new_width, new_height)
  }
}