///|
/// RespValue represents the different types in the RESP (Redis Serialization Protocol).
pub enum RespValue {
  SimpleString(String)
  Error(String)
  Integer(Int64)
  BulkString(String?)
  Array(Array[RespValue]?)
} derive(Debug, ToJson)

///|
/// RespError represents errors occurring during RESP parsing.
pub suberror RespError {
  /// InvalidPrefix occurs when a message does not start with a recognized RESP character.
  InvalidPrefix(Int)
  /// UnexpectedEndOfStream occurs when the reader closes prematurely.
  UnexpectedEndOfStream
  /// MalformedNumber occurs when a numeric field is not a valid number.
  MalformedNumber
  /// MalformedCrlf occurs when a RESP CRLF terminator is invalid.
  MalformedCrlf
} derive(Debug, ToJson)

///|
/// RespParser handles decoding RESP messages from a stream.
pub struct RespParser[R] {
  reader : R
}

///|
/// new creates a new RespParser from an object implementing @io.Reader.
pub fn[R] RespParser::new(reader : R) -> RespParser[R] {
  { reader, }
}

///|
async fn[R : @io.Reader] RespParser::read_byte(
  self : RespParser[R],
) -> Int raise Error {
  let b = @io.Reader::read_exactly(self.reader, 1) catch {
    _ => raise UnexpectedEndOfStream
  }
  b[0].to_int()
}

///|
async fn[R : @io.Reader] RespParser::read_line(
  self : RespParser[R],
) -> String raise Error {
  let bytes : Array[Byte] = Array::new()
  for ;; {
    let b = self.read_byte()
    if b == 13 { // \r
      let next = self.read_byte()
      if next == 10 { // \n
        break
      }
      bytes.push((13).to_byte())
      bytes.push(next.to_byte())
    } else {
      bytes.push(b.to_byte())
    }
  }
  @utf8.decode(Bytes::from_array(bytes))
}

///|
/// expect_crlf consumes and validates a RESP CRLF terminator.
async fn[R : @io.Reader] RespParser::expect_crlf(
  self : RespParser[R],
) -> Unit raise Error {
  let cr = self.read_byte()
  let lf = self.read_byte()

  if cr != 13 || lf != 10 {
    raise MalformedCrlf
  }
}

///|
/// parse_value decodes a single RespValue from the reader.
pub async fn[R : @io.Reader] RespParser::parse_value(
  self : RespParser[R],
) -> RespValue raise Error {
  let prefix = self.read_byte()
  match prefix {
    43 => // '+' Simple String
      SimpleString(self.read_line())
    45 => // '-' Error
      Error(self.read_line())
    58 => { // ':' Integer
      let line = self.read_line()
      Integer(@string.parse_int64(line)) catch {
        _ => raise MalformedNumber
      }
    }
    36 => { // '$' Bulk String
      let len_line = self.read_line()
      let len = @string.parse_int(len_line) catch { _ => raise MalformedNumber }
      if len == -1 {
        BulkString(None)
      } else {
        let buf = @io.Reader::read_exactly(self.reader, len) catch {
          _ => raise UnexpectedEndOfStream
        }
        self.expect_crlf()
        BulkString(Some(@utf8.decode(buf)))
      }
    }
    42 => { // '*' Array
      let len_line = self.read_line()
      let len = @string.parse_int(len_line) catch { _ => raise MalformedNumber }
      if len == -1 {
        Array(None)
      } else {
        let arr = Array::new(capacity=len)
        for i = 0; i < len; i = i + 1 {
          arr.push(self.parse_value())
        }
        Array(Some(arr))
      }
    }
    _ => raise InvalidPrefix(prefix)
  }
}