///|
priv struct ArgsBuilder {
  args : Array[Bytes]
}

///|
fn ArgsBuilder::ArgsBuilder(cmd : Bytes) -> ArgsBuilder {
  { args: [cmd] }
}

///|
fn ArgsBuilder::push_bytes(self : ArgsBuilder, value : Bytes) -> Unit {
  self.args.push(value)
}

///|
fn ArgsBuilder::push_string(self : ArgsBuilder, value : String) -> Unit {
  self.args.push(@encoding/utf8.encode(value))
}

///|
fn ArgsBuilder::push_int(self : ArgsBuilder, value : Int) -> Unit {
  self.push_string(value.to_string())
}

///|
fn ArgsBuilder::push_double(self : ArgsBuilder, value : Double) -> Unit {
  self.push_string(value.to_string())
}

///|
fn ArgsBuilder::push_strings(
  self : ArgsBuilder,
  values : ArrayView[String],
) -> Unit {
  for value in values {
    self.push_string(value)
  }
}

///|
fn ArgsBuilder::push_pairs(
  self : ArgsBuilder,
  items : ArrayView[(String, String)],
) -> Unit {
  for item in items {
    self.push_string(item.0)
    self.push_string(item.1)
  }
}

///|
fn ArgsBuilder::push_scan_options(
  self : ArgsBuilder,
  pattern : String?,
  count : Int?,
) -> Unit {
  if pattern is Some(pattern) {
    self.push_bytes(b"MATCH")
    self.push_string(pattern)
  }
  if count is Some(count) {
    self.push_bytes(b"COUNT")
    self.push_int(count)
  }
}

///|
fn ArgsBuilder::push_limit_options(
  self : ArgsBuilder,
  offset : Int?,
  count : Int?,
) -> Unit raise {
  if offset is Some(offset) && count is Some(count) {
    self.push_bytes(b"LIMIT")
    self.push_int(offset)
    self.push_int(count)
  } else if offset is Some(_) || count is Some(_) {
    raise UnexpectedResponse("offset and count must be supplied together")
  }
}

///|
fn ArgsBuilder::build(self : ArgsBuilder) -> Array[Bytes] {
  self.args
}