///|
/// Simplifies adjacent and redundant HTML nodes.
pub fn simplify_html(nodes : Array[HtmlNode]) -> Array[HtmlNode] {
  let result : Array[HtmlNode] = []
  for node in nodes {
    match simplify_html_node(node) {
      Some(simplified) => append_simplified(result, simplified)
      None => ()
    }
  }
  result
}

///|
fn simplify_html_node(node : HtmlNode) -> HtmlNode? {
  match node {
    TextNode("") => None
    Element(tag~, attributes~, children~, fresh~, separator~) => {
      let children = simplify_html(children)
      if children.is_empty() && !is_void_html_tag(tag) {
        None
      } else {
        Some(Element(tag~, attributes~, children~, fresh~, separator~))
      }
    }
    _ => Some(node)
  }
}

///|
fn append_simplified(result : Array[HtmlNode], node : HtmlNode) -> Unit {
  if result.length() == 0 {
    result.push(node)
  } else {
    let last_index = result.length() - 1
    match (result[last_index], node) {
      (
        Element(
          tag=tag_a,
          attributes=attrs_a,
          children=children_a,
          fresh=fresh_a,
          separator=separator_a
        ),
        Element(
          tag=tag_b,
          attributes=attrs_b,
          children=children_b,
          fresh=false,
          separator=separator_b
        ),
      ) =>
        if html_tag_matches(tag_b, tag_a) && attrs_a == attrs_b {
          let merged = merge_html_children(children_a, children_b, separator_b)
          result[last_index] = Element(
            tag=tag_a,
            attributes=attrs_a,
            children=merged,
            fresh=fresh_a,
            separator=separator_a,
          )
        } else {
          result.push(node)
        }
      _ => result.push(node)
    }
  }
}

///|
fn merge_html_children(
  left : Array[HtmlNode],
  right : Array[HtmlNode],
  separator : String?,
) -> Array[HtmlNode] {
  let merged : Array[HtmlNode] = []
  merged.append(left)
  match separator {
    Some(value) => append_simplified(merged, html_text(value))
    None => ()
  }
  for child in right {
    append_simplified(merged, child)
  }
  merged
}