///|
/// Bolt protocol handshake: the magic preamble and version negotiation.
///
/// A Bolt connection begins with a fixed 20-byte handshake: the 4-byte magic
/// [`MAGIC`], then four 4-byte version proposals in big-endian order. The
/// server replies with a single 4-byte agreed version, or `0x00000000` when no
/// proposed version is supported.
///
/// A version is a 32-bit value laid out `[0x00 reserved][range][minor][major]`
/// (big-endian); `range` is how many consecutive minor versions below `minor`
/// are also accepted. See https://neo4j.com/docs/bolt/current/bolt/handshake/.

///|
/// The 4-byte magic preamble sent at the start of every Bolt connection.
pub const MAGIC : Bytes = b"\x60\x60\xb0\x17"

///|
/// Encode a Bolt version `(major, minor, range)` into its 4-byte wire value.
///
/// `range` is the number of consecutive minor versions *below* `minor` that are
/// also accepted (0 = only the single `major.minor`).
pub fn bolt_version(major : Int, minor : Int, range : Int) -> Int {
  major | (minor << 8) | (range << 16)
}

///|
/// Build the 20-byte handshake message: [`MAGIC`] followed by four version
/// proposals, padded with `0x00000000` when fewer than four are given.
///
/// Versions are sent in priority order; the server picks the first it supports.
pub fn handshake_message(versions : Array[Int]) -> Bytes {
  let buf = Buffer::Buffer()
  buf.write_bytes(MAGIC.exact_view())
  for i in 0..<4 {
    let v = if i < versions.length() { versions[i] } else { 0 }
    buf.write_int_be(v)
  }
  buf.to_bytes()
}

///|
/// Parse the server's 4-byte handshake response into an agreed version.
///
/// Returns `None` when the response is not exactly 4 bytes, or when the server
/// selected `0x00000000` ("no supported version").
pub fn parse_handshake_response(bytes : Bytes) -> Int? {
  if bytes.length() != 4 {
    None
  } else {
    let v = read_uint_be(bytes, 0, 4).to_int()
    if v == 0 {
      None
    } else {
      Some(v)
    }
  }
}