// =============================================================================
// Paint Scroll Package - Scrollable extraction and hit-testing
// =============================================================================

///|
pub(all) struct ScrollableElement {
  id : String
  scroll_width : Double
  scroll_height : Double
  client_width : Double
  client_height : Double
}

///|
pub fn collect_scrollable_elements(
  node : @model.PaintNode,
) -> Array[ScrollableElement] {
  let result : Array[ScrollableElement] = []
  fn collect(
    node : @model.PaintNode,
    result : Array[ScrollableElement],
  ) -> Unit {
    if node.is_scrollable() {
      result.push({
        id: node.id,
        scroll_width: node.scroll_width,
        scroll_height: node.scroll_height,
        client_width: node.width,
        client_height: node.height,
      })
    }
    for child in node.children {
      collect(child, result)
    }
  }

  collect(node, result)
  result
}

///|
pub(all) struct ScrollableHitResult {
  id : String
  x : Double
  y : Double
  width : Double
  height : Double
  scroll_width : Double
  scroll_height : Double
}

///|
pub fn find_scrollable_at(
  node : @model.PaintNode,
  x : Double,
  y : Double,
  parent_x : Double,
  parent_y : Double,
) -> ScrollableHitResult? {
  let abs_x = parent_x + node.x
  let abs_y = parent_y + node.y
  if x < abs_x ||
    x >= abs_x + node.width ||
    y < abs_y ||
    y >= abs_y + node.height {
    return None
  }
  for child in node.children {
    match find_scrollable_at(child, x, y, abs_x, abs_y) {
      Some(result) => return Some(result)
      None => ()
    }
  }
  if node.is_scrollable() {
    return Some({
      id: node.id,
      x: abs_x,
      y: abs_y,
      width: node.width,
      height: node.height,
      scroll_width: node.scroll_width,
      scroll_height: node.scroll_height,
    })
  }
  None
}