///|
/// Limits used when splitting a Line Protocol payload for transport.
pub(all) struct BatchLimits {
  max_points : Int32
  max_bytes : Int32
}

///|
/// Create explicit batch limits.
pub fn BatchLimits::new(max_points : Int32, max_bytes : Int32) -> BatchLimits {
  { max_points, max_bytes, }
}

///|
/// Split a newline-delimited payload without exceeding point or byte limits.
pub fn split_line_protocol(
  text : String,
  limits : BatchLimits,
) -> Result[Array[String], String] {
  if limits.max_points <= 0 {
    return Err("max_points must be positive")
  }
  if limits.max_bytes <= 0 {
    return Err("max_bytes must be positive")
  }

  let batches : Array[String] = Array(capacity=0)
  let current = StringBuilder()
  let mut current_points = 0
  let mut current_bytes = 0

  for raw_line in text.split("\n") {
    let line = raw_line.trim().to_owned()
    if line.is_empty() {
      continue
    }
    let line_bytes = line.length()
    if line_bytes > limits.max_bytes {
      return Err(
        "single point exceeds max_bytes: \{line_bytes} > \{limits.max_bytes}",
      )
    }
    let separator_bytes = if current_points == 0 { 0 } else { 1 }
    let next_points = current_points + 1
    let next_bytes = current_bytes + separator_bytes + line_bytes
    if current_points > 0 &&
      (next_points > limits.max_points || next_bytes > limits.max_bytes) {
      batches.push(current.to_string())
      current.reset()
      current_points = 0
      current_bytes = 0
    }
    if current_points > 0 {
      current.write_char('\n')
    }
    current.write_string(line)
    current_points = current_points + 1
    let separator = if current_points > 1 { 1 } else { 0 }
    current_bytes = current_bytes + line_bytes + separator
  }

  if current_points > 0 {
    batches.push(current.to_string())
  }
  Ok(batches)
}

///|
/// Encode points into bounded Line Protocol batches.
pub fn encode_point_batches(
  points : Array[Point],
  limits : BatchLimits,
) -> Result[Array[String], String] {
  let lines : Array[String] = Array(capacity=points.length())
  for point in points {
    match encode_point(point) {
      Ok(line) => lines.push(line)
      Err(error) => return Err(error)
    }
  }
  split_line_protocol(lines.join("\n"), limits)
}