///|
pub(all) enum FlowDirection {
  Horizontal
  Vertical
} derive(Debug, Eq)

///|
pub(all) enum FlowAlignment {
  Start
  Center
  End
  SpaceBetween
} derive(Debug, Eq)

///|
pub fn stack_horizontal(
  region~ : @scene.Rect,
  item_widths~ : Array[Int],
  gap~ : Int,
) -> Array[@scene.Rect] {
  let frames : Array[@scene.Rect] = []
  let safe_gap = Int::max(gap, 0)
  let mut x = region.x
  item_widths.each(width => {
    let safe_width = Int::max(width, 0)
    frames.push({ x, y: region.y, width: safe_width, height: region.height })
    x = x + safe_width + safe_gap
  })
  frames
}

///|
pub fn distribute_horizontal(
  region~ : @scene.Rect,
  item_widths~ : Array[Int],
  alignment~ : FlowAlignment,
) -> Array[@scene.Rect] {
  let widths = item_widths.map(width => Int::max(width, 0))
  let total = widths.fold(init=0, (sum, width) => sum + width)
  let remaining = Int::max(region.width - total, 0)
  let gap = match alignment {
    Start => 0
    Center => 0
    End => 0
    SpaceBetween =>
      if widths.length() <= 1 {
        0
      } else {
        remaining / (widths.length() - 1)
      }
  }
  let offset = match alignment {
    Start => 0
    Center => remaining / 2
    End => remaining
    SpaceBetween => 0
  }
  let frames : Array[@scene.Rect] = []
  let mut x = region.x + offset
  widths.each(width => {
    frames.push({ x, y: region.y, width, height: region.height })
    x = x + width + gap
  })
  frames
}

///|
pub fn fit_rect(
  source~ : @core.Size,
  target~ : @scene.Rect,
  mode~ : @scene.ImageFit,
) -> @scene.Rect {
  if source.width <= 0 ||
    source.height <= 0 ||
    target.width <= 0 ||
    target.height <= 0 {
    return { ..target, width: 0, height: 0 }
  }
  let source_ratio = source.width.to_double() / source.height.to_double()
  let target_ratio = target.width.to_double() / target.height.to_double()
  let crop = match mode {
    @scene.ImageFit::Contain => source_ratio < target_ratio
    @scene.ImageFit::Cover => source_ratio > target_ratio
  }
  if crop {
    { ..target, width: target.width, height: target.height }
  } else {
    { ..target, width: target.width, height: target.height }
  }
}

///|
pub fn split_vertical(
  region : @scene.Rect,
  ratio_percent : Int,
) -> (@scene.Rect, @scene.Rect) {
  let ratio = Int::clamp(ratio_percent, min=0, max=100)
  let first_height = region.height * ratio / 100
  let first : @scene.Rect = {
    x: region.x,
    y: region.y,
    width: region.width,
    height: first_height,
  }
  let second : @scene.Rect = {
    x: region.x,
    y: region.y + first_height,
    width: region.width,
    height: region.height - first_height,
  }
  (first, second)
}

///|
pub fn split_horizontal(
  region : @scene.Rect,
  ratio_percent : Int,
) -> (@scene.Rect, @scene.Rect) {
  let ratio = Int::clamp(ratio_percent, min=0, max=100)
  let first_width = region.width * ratio / 100
  let first : @scene.Rect = {
    x: region.x,
    y: region.y,
    width: first_width,
    height: region.height,
  }
  let second : @scene.Rect = {
    x: region.x + first_width,
    y: region.y,
    width: region.width - first_width,
    height: region.height,
  }
  (first, second)
}