///|
/// Export-oriented canvas helpers for deterministic previews and fixtures.
pub(all) struct CanvasDigest {
  hash : UInt
  pixels : Int
  width : Int
  height : Int
  alpha_pixels : Int
} derive(Debug)

///|
pub fn CanvasDigest::hash(self : CanvasDigest) -> UInt {
  self.hash
}

///|
pub fn CanvasDigest::pixels(self : CanvasDigest) -> Int {
  self.pixels
}

///|
pub fn CanvasDigest::width(self : CanvasDigest) -> Int {
  self.width
}

///|
pub fn CanvasDigest::height(self : CanvasDigest) -> Int {
  self.height
}

///|
pub fn CanvasDigest::alpha_pixels(self : CanvasDigest) -> Int {
  self.alpha_pixels
}

///|
/// Compute a stable digest for cache keys and regression reports.
pub fn Canvas::digest(self : Canvas) -> CanvasDigest {
  let mut value : UInt = 2166136261
  let mut alpha_pixels = 0
  for color in self.pixels {
    value = (value ^ color.red().to_int().reinterpret_as_uint()) * 16777619
    value = (value ^ color.green().to_int().reinterpret_as_uint()) * 16777619
    value = (value ^ color.blue().to_int().reinterpret_as_uint()) * 16777619
    value = (value ^ color.alpha().to_int().reinterpret_as_uint()) * 16777619
    if color.alpha() > 0 {
      alpha_pixels += 1
    }
  }
  CanvasDigest::{
    hash: value,
    pixels: self.len(),
    width: self.width,
    height: self.height,
    alpha_pixels,
  }
}

///|
/// Return a one-pixel border sample in clockwise order.
pub fn Canvas::border_samples(self : Canvas) -> Array[Rgba] {
  let result : Array[Rgba] = []
  if self.width == 0 || self.height == 0 {
    result
  } else {
    for x in 0.. 1 {
      for y in 1.. 1 {
      for x in 0..<(self.width - 1) {
        result.push(
          self.pixels[(self.height - 1) * self.width + self.width - 2 - x],
        )
      }
    }
    if self.width > 1 {
      for y in 1..<(self.height - 1) {
        result.push(self.pixels[(self.height - 1 - y) * self.width])
      }
    }
    result
  }
}

///|
/// Replace transparent RGB values with a canonical zero color.
pub fn Canvas::canonicalize_transparency(self : Canvas) -> Canvas {
  let result = self.copy()
  for i in 0.. Canvas {
  let safe_columns = if columns < 1 { 1 } else { columns }
  let safe_rows = if rows < 1 { 1 } else { rows }
  let colors = self.color_frequencies(safe_columns * safe_rows)
  let result = Canvas::new(
    width=safe_columns,
    height=safe_rows,
    fill=rgba(0, 0, 0, 0),
  )
  for i, pair in colors {
    result.pixels[i] = pair.0
  }
  result
}

///|
/// Return true when two canvases have equal dimensions and digest.
pub fn canvas_digest_equal(left : Canvas, right : Canvas) -> Bool {
  let a = left.digest()
  let b = right.digest()
  a.width() == b.width() && a.height() == b.height() && a.hash() == b.hash()
}