// The WebSocket opening handshake (RFC 6455 §4.2): a client's Upgrade request carries a
// Sec-WebSocket-Key and an optional list of subprotocols; the server proves it understood the
// protocol by returning Sec-WebSocket-Accept = base64(SHA-1(key + GUID)) in a 101 response, and
// echoes the one subprotocol it selected in Sec-WebSocket-Protocol. Building the 101 here lets
// mooncat honour the negotiated subprotocol in the response — the piece the async transport's
// fixed handshake could not express.

///|
/// The WebSocket handshake GUID appended to the client key before hashing (RFC 6455 §4.2.2).
pub let websocket_guid : String = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

///|
/// The Sec-WebSocket-Accept value for a client's Sec-WebSocket-Key: base64 of the SHA-1 of the
/// key concatenated with the GUID (RFC 6455 §4.2.2).
pub fn websocket_accept_key(sec_websocket_key : String) -> String {
  @utf8.decode_lossy(
    base64_encode(sha1(@utf8.encode(sec_websocket_key + websocket_guid)))[:],
  )
}

///|
/// Select the first client-offered subprotocol the server supports, or `None` if none match
/// (RFC 6455 §4.2.2): the client's order is its preference.
pub fn websocket_select_subprotocol(
  offered : Array[String],
  supported : Array[String],
) -> String? {
  for o in offered {
    for s in supported {
      if o == s {
        return Some(o)
      }
    }
  }
  None
}

///|
/// The 101 Switching Protocols response for a WebSocket upgrade (RFC 6455 §4.2.2): the Upgrade
/// and Connection headers, the computed Sec-WebSocket-Accept, the selected subprotocol when one
/// was negotiated, and any `extra_headers`.
pub fn websocket_handshake_response(
  sec_websocket_key : String,
  subprotocol : String?,
  extra_headers : Array[(String, String)],
) -> Bytes {
  let buf = Buffer()
  buf.write_bytes(@utf8.encode("HTTP/1.1 101 Switching Protocols\r\n"))
  buf.write_bytes(@utf8.encode("Upgrade: websocket\r\n"))
  buf.write_bytes(@utf8.encode("Connection: Upgrade\r\n"))
  buf.write_bytes(
    @utf8.encode(
      "Sec-WebSocket-Accept: " +
      websocket_accept_key(sec_websocket_key) +
      "\r\n",
    ),
  )
  match subprotocol {
    Some(p) =>
      buf.write_bytes(@utf8.encode("Sec-WebSocket-Protocol: " + p + "\r\n"))
    None => ()
  }
  for h in extra_headers {
    buf.write_bytes(@utf8.encode(h.0 + ": " + h.1 + "\r\n"))
  }
  buf.write_bytes(@utf8.encode("\r\n"))
  buf.to_bytes()
}