///|
/// ANSI escape-sequence parser for keyboard and mouse input events.
///
/// Translates raw bytes from the terminal into typed `InputEvent` values.
/// The parser handles printable UTF-8 text, control characters, ANSI CSI
/// sequences (arrow keys, mouse reports), Ctrl-modified keys, and Alt-prefixed
/// keys. Pass a `BytesView` to `parse_input` for a single event, or
/// `parse_all` to drain all complete events at once.

///|
/// A parsed terminal input event.
pub(all) enum InputEvent {
  /// A keyboard event.
  Key(KeyMsg)
  /// An enhanced keyboard-protocol event.
  EnhancedKey(EnhancedKeyMsg)
  /// A mouse event.
  Mouse(MouseMsg)
  /// The terminal window gained focus.
  Focus
  /// The terminal window lost focus.
  Blur
  /// Bracketed paste payload.
  Paste(String)
  /// A reply emitted by a terminal query sequence.
  TerminalReply(TerminalReplyMsg)
  /// Bytes that could not be mapped to a known event.
  Unknown(Bytes)
} derive(Debug, Eq)

///|
/// Result of attempting to parse one event from a byte buffer.
pub(all) enum ParseResult[T] {
  /// Successfully parsed a value; the `Int` is the number of bytes consumed.
  Ok(T, Int)
  /// The buffer ended mid-sequence; supply more bytes and retry.
  Incomplete
  /// The byte sequence is definitively malformed.
  Invalid(String)
} derive(Debug, Eq)

///|
fn unknown_event(bv : BytesView, consumed : Int) -> InputEvent {
  Unknown(Bytes::from_array(bv[0:consumed].to_array()))
}

///|
fn unknown_reply_event(bv : BytesView, consumed : Int) -> InputEvent {
  TerminalReply(UnknownReply(Bytes::from_array(bv[0:consumed].to_array())))
}

///|
priv enum Utf8Scalar {
  Utf8Ok(Char, Int)
  Utf8Incomplete
  Utf8Invalid(String)
}

///|
fn is_utf8_continuation(b : Int) -> Bool {
  b >= 0x80 && b <= 0xBF
}

///|
fn in_byte_range(b : Int, first : Int, last : Int) -> Bool {
  b >= first && b <= last
}

///|
fn utf8_invalid(message : String) -> Utf8Scalar {
  Utf8Invalid(message)
}

///|
fn decode_utf8_scalar(bv : BytesView) -> Utf8Scalar {
  let n = bv.length()
  if n == 0 {
    return Utf8Incomplete
  }
  let b0 = bv[0].to_int()
  if b0 <= 0x7F {
    return Utf8Ok(b0.unsafe_to_char(), 1)
  }
  if b0 >= 0xC2 && b0 <= 0xDF {
    if n < 2 {
      return Utf8Incomplete
    }
    let b1 = bv[1].to_int()
    if !is_utf8_continuation(b1) {
      return utf8_invalid("invalid UTF-8 continuation byte \{b1}")
    }
    let code = ((b0 & 0x1F) << 6) | (b1 & 0x3F)
    return Utf8Ok(code.unsafe_to_char(), 2)
  }
  if b0 >= 0xE0 && b0 <= 0xEF {
    if n < 2 {
      return Utf8Incomplete
    }
    let b1 = bv[1].to_int()
    let b1_ok = if b0 == 0xE0 {
      in_byte_range(b1, 0xA0, 0xBF)
    } else if b0 == 0xED {
      in_byte_range(b1, 0x80, 0x9F)
    } else {
      is_utf8_continuation(b1)
    }
    if !b1_ok {
      return utf8_invalid("invalid UTF-8 continuation byte \{b1}")
    }
    if n < 3 {
      return Utf8Incomplete
    }
    let b2 = bv[2].to_int()
    if !is_utf8_continuation(b2) {
      return utf8_invalid("invalid UTF-8 continuation byte \{b2}")
    }
    let code = ((b0 & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F)
    return Utf8Ok(code.unsafe_to_char(), 3)
  }
  if b0 >= 0xF0 && b0 <= 0xF4 {
    if n < 2 {
      return Utf8Incomplete
    }
    let b1 = bv[1].to_int()
    let b1_ok = if b0 == 0xF0 {
      in_byte_range(b1, 0x90, 0xBF)
    } else if b0 == 0xF4 {
      in_byte_range(b1, 0x80, 0x8F)
    } else {
      is_utf8_continuation(b1)
    }
    if !b1_ok {
      return utf8_invalid("invalid UTF-8 continuation byte \{b1}")
    }
    if n < 3 {
      return Utf8Incomplete
    }
    let b2 = bv[2].to_int()
    if !is_utf8_continuation(b2) {
      return utf8_invalid("invalid UTF-8 continuation byte \{b2}")
    }
    if n < 4 {
      return Utf8Incomplete
    }
    let b3 = bv[3].to_int()
    if !is_utf8_continuation(b3) {
      return utf8_invalid("invalid UTF-8 continuation byte \{b3}")
    }
    let code = ((b0 & 0x07) << 18) |
      ((b1 & 0x3F) << 12) |
      ((b2 & 0x3F) << 6) |
      (b3 & 0x3F)
    return Utf8Ok(code.unsafe_to_char(), 4)
  }
  utf8_invalid("invalid UTF-8 leading byte \{b0}")
}

///|
fn is_text_scalar(ch : Char) -> Bool {
  ch != '\u001b' && !ch.is_control()
}

///|
fn key_text_event(text : String) -> InputEvent {
  let cluster = @internal.grapheme_slice(text, 0, 1)
  let chars = cluster.to_array()
  let boundaries = @internal.grapheme_boundaries(cluster)
  let _width = @internal.display_width(cluster)
  if chars.length() == 1 && boundaries.length() == 2 {
    Key(Char(chars[0]))
  } else {
    Key(Text(cluster))
  }
}

///|
fn emit_text_event(
  chars : Array[Char],
  byte_offsets : Array[Int],
) -> ParseResult[InputEvent] {
  let text = String::from_array(chars)
  let boundaries = @internal.grapheme_boundaries(text)
  let cluster_chars = if boundaries.length() > 1 {
    boundaries[1]
  } else {
    chars.length()
  }
  let cluster = @internal.grapheme_slice(text, 0, 1)
  let consumed = byte_offsets[cluster_chars]
  Ok(key_text_event(cluster), consumed)
}

///|
fn parse_text_event(bv : BytesView) -> ParseResult[InputEvent] {
  let chars : Array[Char] = []
  let byte_offsets : Array[Int] = [0]
  let total = bv.length()
  let mut offset = 0
  while offset < total {
    match decode_utf8_scalar(bv[offset:total]) {
      Utf8Ok(ch, consumed) => {
        if !is_text_scalar(ch) {
          if chars.is_empty() {
            return Ok(unknown_event(bv, consumed), consumed)
          }
          return emit_text_event(chars, byte_offsets)
        }
        chars.push(ch)
        offset = offset + consumed
        byte_offsets.push(offset)
        let text = String::from_array(chars)
        let boundaries = @internal.grapheme_boundaries(text)
        if boundaries.length() > 2 {
          return emit_text_event(chars, byte_offsets)
        }
      }
      Utf8Incomplete => {
        if chars.is_empty() {
          return Incomplete
        }
        return emit_text_event(chars, byte_offsets)
      }
      Utf8Invalid(message) => {
        if chars.is_empty() {
          return Invalid(message)
        }
        return emit_text_event(chars, byte_offsets)
      }
    }
  }
  if chars.is_empty() {
    Incomplete
  } else {
    emit_text_event(chars, byte_offsets)
  }
}

///|
fn parse_bracketed_paste(
  bv : BytesView,
  payload_start : Int,
) -> ParseResult[InputEvent] {
  let total = bv.length()
  let mut i = payload_start
  while i + 5 < total {
    if bv[i].to_int() == 0x1B &&
      bv[i + 1].to_int() == 0x5B &&
      bv[i + 2].to_int() == 0x32 &&
      bv[i + 3].to_int() == 0x30 &&
      bv[i + 4].to_int() == 0x31 &&
      bv[i + 5].to_int() == 0x7E {
      let pasted = Bytes::from_array(bv[payload_start:i].to_array())
      return Ok(Paste(@utf8.decode_lossy(pasted)), i + 6)
    }
    i = i + 1
  }
  Incomplete
}

///|
fn mouse_modifiers(cb : Int) -> Array[MouseModifier] {
  let modifiers : Array[MouseModifier] = []
  if (cb & 0x04) != 0 {
    modifiers.push(MouseShift)
  }
  if (cb & 0x08) != 0 {
    modifiers.push(MouseAlt)
  }
  if (cb & 0x10) != 0 {
    modifiers.push(MouseCtrl)
  }
  modifiers
}

///|
fn mouse_button(cb : Int) -> MouseButton {
  let low = cb & 0x03
  if (cb & 0x40) != 0 {
    match low {
      0 => MouseWheelUp
      1 => MouseWheelDown
      2 => MouseWheelLeft
      _ => MouseWheelRight
    }
  } else {
    match low {
      0 => MouseLeft
      1 => MouseMiddle
      2 => MouseRight
      _ => MouseNoButton
    }
  }
}

///|
fn is_no_button_report(cb : Int) -> Bool {
  (cb & 0x40) == 0 && (cb & 0x03) == 0x03
}

///|
fn parse_sgr_mouse(bv : BytesView) -> ParseResult[InputEvent] {
  let n = bv.length()
  let mut final_index = 3
  while final_index < n {
    let b = bv[final_index].to_int()
    if b == 0x4D || b == 0x6D {
      let values : Array[Int] = []
      let mut value = 0
      let mut has_digit = false
      let mut j = 3
      while j < final_index {
        let part = bv[j].to_int()
        if part >= 0x30 && part <= 0x39 {
          value = value * 10 + part - 0x30
          has_digit = true
        } else if part == 0x3B {
          if !has_digit {
            return Invalid("empty SGR mouse parameter")
          }
          values.push(value)
          value = 0
          has_digit = false
        } else {
          return Invalid("invalid byte \{part} in SGR mouse sequence")
        }
        j = j + 1
      }
      if !has_digit {
        return Invalid("empty SGR mouse parameter")
      }
      values.push(value)
      if values.length() != 3 {
        return Invalid("SGR mouse report must contain Cb, Cx, and Cy")
      }
      let cb = values[0]
      let col = values[1]
      let row = values[2]
      if col <= 0 || row <= 0 {
        return Invalid("SGR mouse coordinates must be 1-based")
      }
      let is_wheel = (cb & 0x40) != 0
      let action = if is_wheel {
        MouseWheel
      } else if b == 0x6D {
        MouseRelease
      } else if (cb & 0x20) != 0 {
        MouseMotion
      } else {
        MousePress
      }
      if is_no_button_report(cb) && action != MouseMotion {
        return Ok(unknown_event(bv, final_index + 1), final_index + 1)
      }
      let button = mouse_button(cb)
      return Ok(
        Mouse({ button, action, modifiers: mouse_modifiers(cb), col, row }),
        final_index + 1,
      )
    } else if (b >= 0x30 && b <= 0x39) || b == 0x3B {
      final_index = final_index + 1
    } else {
      return Invalid("invalid byte \{b} in SGR mouse sequence")
    }
  }
  Incomplete
}

///|
priv enum EnhancedKeyParse {
  EnhancedKeyOk(InputEvent)
  EnhancedKeyUnknown
  EnhancedKeyInvalid(String)
}

///|
fn enhanced_key_code(value : Int) -> EnhancedKeyCode {
  if value >= 57344 && value <= 63743 {
    FunctionalKey(value)
  } else {
    UnicodeKey(value)
  }
}

///|
fn parse_decimal_segment(bv : BytesView, start : Int, end : Int) -> Int? {
  if start >= end {
    return None
  }
  let mut value = 0
  let mut i = start
  while i < end {
    let b = bv[i].to_int()
    if b < 0x30 || b > 0x39 {
      return None
    }
    value = value * 10 + b - 0x30
    i = i + 1
  }
  Some(value)
}

///|
fn parse_decimal_params(bv : BytesView, start : Int, end : Int) -> Array[Int]? {
  if start >= end {
    return None
  }
  let params : Array[Int] = []
  let mut segment_start = start
  let mut i = start
  while i <= end {
    if i == end || bv[i].to_int() == 0x3B {
      match parse_decimal_segment(bv, segment_start, i) {
        Some(value) => params.push(value)
        None => return None
      }
      segment_start = i + 1
    }
    i = i + 1
  }
  Some(params)
}

///|
fn parse_cursor_position_reply(
  bv : BytesView,
  final_index : Int,
) -> CursorPositionReply? {
  let mut semicolon = -1
  let mut i = 2
  while i < final_index {
    if bv[i].to_int() == 0x3B {
      if semicolon >= 0 {
        return None
      }
      semicolon = i
    }
    i = i + 1
  }
  if semicolon < 0 {
    return None
  }
  let row = match parse_decimal_segment(bv, 2, semicolon) {
    Some(value) => value
    None => return None
  }
  let col = match parse_decimal_segment(bv, semicolon + 1, final_index) {
    Some(value) => value
    None => return None
  }
  if row <= 0 || col <= 0 {
    return None
  }
  Some({ row, col })
}

///|
fn parse_device_attributes_reply(
  bv : BytesView,
  final_index : Int,
) -> TerminalReplyMsg? {
  if final_index <= 3 {
    return None
  }
  let prefix = bv[2].to_int()
  if prefix == 0x3F {
    match parse_decimal_params(bv, 3, final_index) {
      Some(params) => Some(DeviceAttributes(params))
      None => None
    }
  } else if prefix == 0x3E {
    match parse_decimal_params(bv, 3, final_index) {
      Some(params) => Some(SecondaryDeviceAttributes(params))
      None => None
    }
  } else {
    None
  }
}

///|
fn is_csi_unknown_reply(
  bv : BytesView,
  final_index : Int,
  final_byte : Int,
) -> Bool {
  if final_byte == 0x52 ||
    final_byte == 0x63 ||
    final_byte == 0x6E ||
    final_byte == 0x74 {
    return true
  }
  if final_index > 2 {
    let first = bv[2].to_int()
    first == 0x3F || first == 0x3E
  } else {
    false
  }
}

///|
fn decode_slice_lossy(bv : BytesView, start : Int, end : Int) -> String {
  @utf8.decode_lossy(Bytes::from_array(bv[start:end].to_array()))
}

///|
fn is_osc_command_start(b : Int) -> Bool {
  b >= 0x30 && b <= 0x39
}

///|
fn parse_osc_color_reply(
  bv : BytesView,
  payload_start : Int,
  payload_end : Int,
) -> TerminalColorReply? {
  let len = payload_end - payload_start
  if len >= 3 &&
    bv[payload_start].to_int() == 0x31 &&
    bv[payload_start + 1].to_int() == 0x30 &&
    bv[payload_start + 2].to_int() == 0x3B {
    return Some(
      ForegroundColor(decode_slice_lossy(bv, payload_start + 3, payload_end)),
    )
  }
  if len >= 3 &&
    bv[payload_start].to_int() == 0x31 &&
    bv[payload_start + 1].to_int() == 0x31 &&
    bv[payload_start + 2].to_int() == 0x3B {
    return Some(
      BackgroundColor(decode_slice_lossy(bv, payload_start + 3, payload_end)),
    )
  }
  if len >= 4 &&
    bv[payload_start].to_int() == 0x34 &&
    bv[payload_start + 1].to_int() == 0x3B {
    let index_start = payload_start + 2
    let mut separator = -1
    let mut i = index_start
    while i < payload_end {
      if bv[i].to_int() == 0x3B {
        separator = i
        break
      }
      i = i + 1
    }
    if separator > index_start {
      match parse_decimal_segment(bv, index_start, separator) {
        Some(index) =>
          return Some(
            PaletteColor(
              index,
              decode_slice_lossy(bv, separator + 1, payload_end),
            ),
          )
        None => ()
      }
    }
  }
  None
}

///|
fn base64_value(b : Int) -> Int? {
  if b >= 0x41 && b <= 0x5A {
    Some(b - 0x41)
  } else if b >= 0x61 && b <= 0x7A {
    Some(b - 0x61 + 26)
  } else if b >= 0x30 && b <= 0x39 {
    Some(b - 0x30 + 52)
  } else if b == 0x2B {
    Some(62)
  } else if b == 0x2F {
    Some(63)
  } else {
    None
  }
}

///|
fn base64_digit(value : Int) -> Char {
  if value < 26 {
    (0x41 + value).unsafe_to_char()
  } else if value < 52 {
    (0x61 + value - 26).unsafe_to_char()
  } else if value < 62 {
    (0x30 + value - 52).unsafe_to_char()
  } else if value == 62 {
    '+'
  } else if value == 63 {
    '/'
  } else {
    abort("base64 digit out of range")
  }
}

///|
fn encode_base64_utf8(input : String) -> String {
  let bytes = @utf8.encode(input)
  let len = bytes.length()
  let buf = StringBuilder::new(size_hint=(len + 2) / 3 * 4)
  let mut i = 0
  while i < len {
    let a = bytes[i].to_int()
    let has_b = i + 1 < len
    let has_c = i + 2 < len
    let b = if has_b { bytes[i + 1].to_int() } else { 0 }
    let c = if has_c { bytes[i + 2].to_int() } else { 0 }
    buf.write_char(base64_digit((a >> 2) & 0x3F))
    buf.write_char(base64_digit(((a & 0x03) << 4) | ((b >> 4) & 0x0F)))
    if has_b {
      buf.write_char(base64_digit(((b & 0x0F) << 2) | ((c >> 6) & 0x03)))
    } else {
      buf.write_char('=')
    }
    if has_c {
      buf.write_char(base64_digit(c & 0x3F))
    } else {
      buf.write_char('=')
    }
    i = i + 3
  }
  buf.to_string()
}

///|
fn decode_base64_slice(bv : BytesView, start : Int, end : Int) -> Bytes? {
  let values : Array[Int] = []
  let mut saw_padding = false
  let mut i = start
  while i < end {
    let b = bv[i].to_int()
    if b == 0x3D {
      saw_padding = true
      values.push(-1)
    } else {
      if saw_padding {
        return None
      }
      match base64_value(b) {
        Some(value) => values.push(value)
        None => return None
      }
    }
    i = i + 1
  }
  if values.length() == 0 {
    return Some(Bytes::new(0))
  }
  match values.length() % 4 {
    0 => ()
    2 => {
      values.push(-1)
      values.push(-1)
    }
    3 => values.push(-1)
    _ => return None
  }
  let decoded : Array[Byte] = []
  let mut index = 0
  while index < values.length() {
    let a = values[index]
    let b = values[index + 1]
    let c = values[index + 2]
    let d = values[index + 3]
    if a < 0 || b < 0 {
      return None
    }
    if (c < 0 || d < 0) && index + 4 != values.length() {
      return None
    }
    decoded.push((((a << 2) | (b >> 4)) & 0xFF).to_byte())
    if c >= 0 {
      decoded.push(((((b & 0x0F) << 4) | (c >> 2)) & 0xFF).to_byte())
    }
    if c >= 0 && d >= 0 {
      decoded.push(((((c & 0x03) << 6) | d) & 0xFF).to_byte())
    } else if c < 0 && d >= 0 {
      return None
    }
    index = index + 4
  }
  Some(Bytes::from_array(decoded))
}

///|
fn decode_utf8_strict(bytes : Bytes) -> String? {
  let bv = bytes[:]
  let mut offset = 0
  while offset < bv.length() {
    match decode_utf8_scalar(bv[offset:bv.length()]) {
      Utf8Ok(_, consumed) => offset = offset + consumed
      Utf8Incomplete | Utf8Invalid(_) => return None
    }
  }
  Some(@utf8.decode_lossy(bytes))
}

///|
fn parse_osc_clipboard_reply(
  bv : BytesView,
  payload_start : Int,
  payload_end : Int,
) -> ClipboardReply? {
  let len = payload_end - payload_start
  if len < 4 ||
    bv[payload_start].to_int() != 0x35 ||
    bv[payload_start + 1].to_int() != 0x32 ||
    bv[payload_start + 2].to_int() != 0x3B {
    return None
  }
  let selection_start = payload_start + 3
  let mut separator = -1
  let mut i = selection_start
  while i < payload_end {
    if bv[i].to_int() == 0x3B {
      separator = i
      break
    }
    i = i + 1
  }
  if separator < 0 {
    return None
  }
  let selection = parse_clipboard_selection_code(
    decode_slice_lossy(bv, selection_start, separator),
  )
  let raw = decode_slice_lossy(bv, separator + 1, payload_end)
  let payload = match decode_base64_slice(bv, separator + 1, payload_end) {
    Some(decoded) =>
      match decode_utf8_strict(decoded) {
        Some(text) => DecodedClipboardText(text)
        None => RawClipboardData(raw)
      }
    None => RawClipboardData(raw)
  }
  Some({ selection, payload })
}

///|
fn parse_osc_payload(
  bv : BytesView,
  payload_start : Int,
  payload_end : Int,
  consumed : Int,
) -> ParseResult[InputEvent] {
  match parse_osc_clipboard_reply(bv, payload_start, payload_end) {
    Some(reply) => Ok(TerminalReply(Clipboard(reply)), consumed)
    None =>
      match parse_osc_color_reply(bv, payload_start, payload_end) {
        Some(color) => Ok(TerminalReply(Color(color)), consumed)
        None => Ok(unknown_reply_event(bv, consumed), consumed)
      }
  }
}

///|
fn parse_osc(bv : BytesView) -> ParseResult[InputEvent] {
  let n = bv.length()
  if n < 3 {
    return Incomplete
  }
  let mut i = 2
  while i < n {
    let b = bv[i].to_int()
    if b == 0x07 {
      return parse_osc_payload(bv, 2, i, i + 1)
    }
    if b == 0x1B {
      if i + 1 >= n {
        return Incomplete
      }
      if bv[i + 1].to_int() == 0x5C {
        return parse_osc_payload(bv, 2, i, i + 2)
      }
    }
    i = i + 1
  }
  Incomplete
}

///|
fn hex_value(b : Int) -> Int? {
  if b >= 0x30 && b <= 0x39 {
    Some(b - 0x30)
  } else if b >= 0x41 && b <= 0x46 {
    Some(b - 0x41 + 10)
  } else if b >= 0x61 && b <= 0x66 {
    Some(b - 0x61 + 10)
  } else {
    None
  }
}

///|
fn decode_hex_slice(bv : BytesView, start : Int, end : Int) -> Bytes? {
  if (end - start) % 2 != 0 {
    return None
  }
  let decoded : Array[Byte] = []
  let mut i = start
  while i < end {
    let high = match hex_value(bv[i].to_int()) {
      Some(value) => value
      None => return None
    }
    let low = match hex_value(bv[i + 1].to_int()) {
      Some(value) => value
      None => return None
    }
    decoded.push(((high << 4) | low).to_byte())
    i = i + 2
  }
  Some(Bytes::from_array(decoded))
}

///|
fn decode_hex_text(bv : BytesView, start : Int, end : Int) -> String? {
  if start >= end {
    return None
  }
  match decode_hex_slice(bv, start, end) {
    Some(bytes) => Some(@utf8.decode_lossy(bytes))
    None => None
  }
}

///|
fn parse_capability_reply(
  bv : BytesView,
  payload_start : Int,
  payload_end : Int,
) -> CapabilityReply? {
  let len = payload_end - payload_start
  if len < 4 ||
    bv[payload_start + 1].to_int() != 0x2B ||
    bv[payload_start + 2].to_int() != 0x72 {
    return None
  }
  let status = bv[payload_start].to_int()
  let valid = if status == 0x31 {
    true
  } else if status == 0x30 {
    false
  } else {
    return None
  }
  let data_start = payload_start + 3
  let mut item_end = payload_end
  let mut separator = -1
  let mut i = data_start
  while i < payload_end {
    let b = bv[i].to_int()
    if b == 0x3B {
      item_end = i
      break
    }
    if b == 0x3D {
      if separator >= 0 {
        return None
      }
      separator = i
    }
    i = i + 1
  }
  let name_end = if separator >= 0 { separator } else { item_end }
  let name = match decode_hex_text(bv, data_start, name_end) {
    Some(decoded) => decoded
    None => return None
  }
  let value = if valid {
    if separator < 0 || separator + 1 >= item_end {
      return None
    }
    match decode_hex_text(bv, separator + 1, item_end) {
      Some(decoded) => Some(decoded)
      None => return None
    }
  } else {
    if separator >= 0 {
      return None
    }
    None
  }
  Some({ name, value, valid })
}

///|
fn parse_dcs_payload(
  bv : BytesView,
  payload_start : Int,
  payload_end : Int,
  consumed : Int,
) -> ParseResult[InputEvent] {
  match parse_capability_reply(bv, payload_start, payload_end) {
    Some(reply) => Ok(TerminalReply(Capability(reply)), consumed)
    None => Ok(unknown_reply_event(bv, consumed), consumed)
  }
}

///|
fn parse_dcs(bv : BytesView) -> ParseResult[InputEvent] {
  let n = bv.length()
  if n < 3 {
    return Incomplete
  }
  let mut i = 2
  while i < n {
    let b = bv[i].to_int()
    if b == 0x1B {
      if i + 1 >= n {
        return Incomplete
      }
      if bv[i + 1].to_int() == 0x5C {
        return parse_dcs_payload(bv, 2, i, i + 2)
      }
    }
    i = i + 1
  }
  Incomplete
}

///|
fn parse_key_code_segment(
  bv : BytesView,
  start : Int,
  end : Int,
) -> EnhancedKeyCode? {
  match parse_decimal_segment(bv, start, end) {
    Some(value) => Some(enhanced_key_code(value))
    None => None
  }
}

///|
fn parse_enhanced_key_code_triple(
  bv : BytesView,
  start : Int,
  end : Int,
) -> EnhancedKeyParse {
  if start >= end {
    return EnhancedKeyUnknown
  }
  let first = bv[start].to_int()
  if first < 0x30 || first > 0x39 {
    return EnhancedKeyUnknown
  }
  let colon_positions : Array[Int] = []
  let mut i = start
  while i < end {
    if bv[i].to_int() == 0x3A {
      colon_positions.push(i)
    }
    i = i + 1
  }
  if colon_positions.length() > 2 {
    return EnhancedKeyInvalid("CSI-u key code contains too many alternates")
  }
  let primary_end = if colon_positions.length() == 0 {
    end
  } else {
    colon_positions[0]
  }
  let primary = match parse_key_code_segment(bv, start, primary_end) {
    Some(code) => code
    None => return EnhancedKeyInvalid("invalid CSI-u primary key code")
  }
  let shifted = if colon_positions.length() >= 1 {
    let shifted_start = colon_positions[0] + 1
    let shifted_end = if colon_positions.length() == 1 {
      end
    } else {
      colon_positions[1]
    }
    match parse_key_code_segment(bv, shifted_start, shifted_end) {
      Some(code) => Some(code)
      None => return EnhancedKeyInvalid("invalid CSI-u shifted key code")
    }
  } else {
    None
  }
  let base_layout = if colon_positions.length() == 2 {
    match parse_key_code_segment(bv, colon_positions[1] + 1, end) {
      Some(code) => Some(code)
      None => return EnhancedKeyInvalid("invalid CSI-u base-layout key code")
    }
  } else {
    None
  }
  EnhancedKeyOk(
    EnhancedKey({
      code: primary,
      shifted,
      base_layout,
      modifiers: [],
      event_type: KeyPress,
      text_codepoints: [],
    }),
  )
}

///|
fn parse_enhanced_event_type(value : Int) -> EnhancedKeyEventType? {
  match value {
    1 => Some(KeyPress)
    2 => Some(KeyRepeat)
    3 => Some(KeyRelease)
    _ => None
  }
}

///|
fn enhanced_key_modifiers(encoded : Int) -> Array[EnhancedKeyModifier]? {
  if encoded < 1 {
    return None
  }
  let bits = encoded - 1
  let modifiers : Array[EnhancedKeyModifier] = []
  if (bits & 0x01) != 0 {
    modifiers.push(KeyShift)
  }
  if (bits & 0x02) != 0 {
    modifiers.push(KeyAlt)
  }
  if (bits & 0x04) != 0 {
    modifiers.push(KeyCtrl)
  }
  if (bits & 0x08) != 0 {
    modifiers.push(KeySuper)
  }
  if (bits & 0x10) != 0 {
    modifiers.push(KeyHyper)
  }
  if (bits & 0x20) != 0 {
    modifiers.push(KeyMeta)
  }
  if (bits & 0x40) != 0 {
    modifiers.push(KeyCapsLock)
  }
  if (bits & 0x80) != 0 {
    modifiers.push(KeyNumLock)
  }
  Some(modifiers)
}

///|
fn parse_enhanced_key_modifiers(
  bv : BytesView,
  start : Int,
  end : Int,
) -> (Array[EnhancedKeyModifier], EnhancedKeyEventType)? {
  if start >= end {
    return None
  }
  let mut colon_index = -1
  let mut i = start
  while i < end {
    if bv[i].to_int() == 0x3A {
      if colon_index >= 0 {
        return None
      }
      colon_index = i
    }
    i = i + 1
  }
  let modifiers_end = if colon_index >= 0 { colon_index } else { end }
  let modifiers = if start == modifiers_end {
    return None
  } else {
    match parse_decimal_segment(bv, start, modifiers_end) {
      Some(value) =>
        match enhanced_key_modifiers(value) {
          Some(modifiers) => modifiers
          None => return None
        }
      None => return None
    }
  }
  let event_type = if colon_index >= 0 {
    match parse_decimal_segment(bv, colon_index + 1, end) {
      Some(value) =>
        match parse_enhanced_event_type(value) {
          Some(kind) => kind
          None => return None
        }
      None => return None
    }
  } else {
    KeyPress
  }
  Some((modifiers, event_type))
}

///|
fn parse_enhanced_text_codepoints(
  bv : BytesView,
  start : Int,
  end : Int,
) -> Array[Int]? {
  let codepoints : Array[Int] = []
  if start >= end {
    return None
  }
  let mut segment_start = start
  let mut i = start
  while i <= end {
    if i == end || bv[i].to_int() == 0x3A {
      match parse_decimal_segment(bv, segment_start, i) {
        Some(value) => codepoints.push(value)
        None => return None
      }
      segment_start = i + 1
    }
    i = i + 1
  }
  Some(codepoints)
}

///|
fn parse_enhanced_key(bv : BytesView, final_index : Int) -> EnhancedKeyParse {
  let start = 2
  let end = final_index
  let semicolons : Array[Int] = []
  let mut i = start
  while i < end {
    if bv[i].to_int() == 0x3B {
      semicolons.push(i)
    }
    i = i + 1
  }
  if semicolons.length() > 2 {
    return EnhancedKeyInvalid("CSI-u key event has too many parameters")
  }
  let key_end = if semicolons.length() == 0 { end } else { semicolons[0] }
  let key_data = match parse_enhanced_key_code_triple(bv, start, key_end) {
    EnhancedKeyOk(EnhancedKey(key)) => key
    EnhancedKeyOk(_) => return EnhancedKeyInvalid("invalid CSI-u key payload")
    EnhancedKeyUnknown => return EnhancedKeyUnknown
    EnhancedKeyInvalid(message) => return EnhancedKeyInvalid(message)
  }
  let (modifiers, event_type) = if semicolons.length() >= 1 {
    let modifiers_start = semicolons[0] + 1
    let modifiers_end = if semicolons.length() == 1 {
      end
    } else {
      semicolons[1]
    }
    match parse_enhanced_key_modifiers(bv, modifiers_start, modifiers_end) {
      Some(parsed) => parsed
      None => return EnhancedKeyInvalid("invalid CSI-u modifiers or event type")
    }
  } else {
    ([], KeyPress)
  }
  let text_codepoints = if semicolons.length() == 2 {
    match parse_enhanced_text_codepoints(bv, semicolons[1] + 1, end) {
      Some(codepoints) => codepoints
      None => return EnhancedKeyInvalid("invalid CSI-u text codepoint list")
    }
  } else {
    []
  }
  EnhancedKeyOk(
    EnhancedKey({ ..key_data, modifiers, event_type, text_codepoints }),
  )
}

///|
/// Parse an ANSI CSI sequence starting at `bv[0]` (which must be ESC).
/// `bv[1]` must be `[` (0x5B) before calling this function.
fn parse_csi(bv : BytesView) -> ParseResult[InputEvent] {
  let n = bv.length()
  // Need at least ESC [ 
  if n < 3 {
    return Incomplete
  }
  // SGR mouse report: ESC [ < Cb ; Cx ; Cy (M|m)
  if bv[2].to_int() == 0x3C {
    return parse_sgr_mouse(bv)
  }
  // Scan parameter / intermediate bytes until we hit the final byte.
  // Parameter bytes: 0x30-0x3F, intermediate bytes: 0x20-0x2F.
  // Final byte: 0x40-0x7E.
  let mut i = 2
  while i < n {
    let b = bv[i].to_int()
    if b >= 0x40 && b <= 0x7E {
      let consumed = i + 1
      let params = @utf8.decode_lossy(Bytes::from_array(bv[2:i].to_array()))
      if b == 0x75 {
        match parse_enhanced_key(bv, i) {
          EnhancedKeyOk(evt) => return Ok(evt, consumed)
          EnhancedKeyUnknown => ()
          EnhancedKeyInvalid(message) => return Invalid(message)
        }
      }
      if b == 0x52 {
        match parse_cursor_position_reply(bv, i) {
          Some(reply) =>
            return Ok(TerminalReply(CursorPosition(reply)), consumed)
          None => return Ok(unknown_reply_event(bv, consumed), consumed)
        }
      }
      if b == 0x63 {
        match parse_device_attributes_reply(bv, i) {
          Some(reply) => return Ok(TerminalReply(reply), consumed)
          None => return Ok(unknown_reply_event(bv, consumed), consumed)
        }
      }
      if is_csi_unknown_reply(bv, i, b) {
        return Ok(unknown_reply_event(bv, consumed), consumed)
      }
      let evt : InputEvent = match (b, params) {
        (0x41, "") => Key(Special("up"))
        (0x42, "") => Key(Special("down"))
        (0x43, "") => Key(Special("right"))
        (0x44, "") => Key(Special("left"))
        (0x46, "") => Key(Special("end"))
        (0x48, "") => Key(Special("home"))
        (0x49, "") => Focus
        (0x4F, "") => Blur
        (0x5A, "") => Key(Modified("shift", "tab"))
        (0x7E, "2") => Key(Special("insert"))
        (0x7E, "3") => Key(Special("delete"))
        (0x7E, "5") => Key(Special("pageup"))
        (0x7E, "6") => Key(Special("pagedown"))
        (0x7E, "200") => return parse_bracketed_paste(bv, consumed)
        _ => unknown_event(bv, consumed)
      }
      return Ok(evt, consumed)
    } else if b >= 0x20 && b <= 0x3F {
      i = i + 1
    } else {
      // Byte is not a valid parameter/intermediate/final byte — definitively malformed.
      return Invalid("invalid byte \{b} in CSI sequence at position \{i}")
    }
  }
  // Reached end of buffer without finding the final byte.
  Incomplete
}

///|
/// Parse one `InputEvent` from the front of `bv`.
///
/// Returns `Ok(event, bytes_consumed)` on success, `Incomplete` when more
/// bytes are needed to complete the current sequence, or `Invalid` when a CSI
/// sequence contains a definitively malformed parameter byte. Unrecognised but
/// structurally valid sequences are returned as `Ok(Unknown(...), n)` so callers
/// can distinguish protocol errors from merely unknown sequences.
pub fn parse_input(bv : BytesView) -> ParseResult[InputEvent] {
  if bv.length() == 0 {
    return Incomplete
  }
  let b0 = bv[0].to_int()
  // Printable UTF-8 text, including ASCII space through tilde.
  if (b0 >= 0x20 && b0 <= 0x7E) || b0 >= 0x80 {
    return parse_text_event(bv)
  }
  // DEL (0x7F) and BS (0x08) → backspace
  if b0 == 0x7F || b0 == 0x08 {
    return Ok(Key(Special("backspace")), 1)
  }
  // CR (0x0D) → enter
  if b0 == 0x0D {
    return Ok(Key(Special("enter")), 1)
  }
  // HT (0x09) → tab
  if b0 == 0x09 {
    return Ok(Key(Special("tab")), 1)
  }
  // ESC (0x1B): could be standalone, Alt+key, or start of CSI sequence
  if b0 == 0x1B {
    let n = bv.length()
    if n == 1 {
      // Could be standalone ESC or start of a sequence; need more bytes.
      return Incomplete
    }
    let b1 = bv[1].to_int()
    // ESC [ → CSI sequence
    if b1 == 0x5B {
      return parse_csi(bv)
    }
    // ESC ] plus a digit starts an OSC reply/control string; bare ESC ]
    // stays available for the Alt+] key path below.
    if b1 == 0x5D && n > 2 && is_osc_command_start(bv[2].to_int()) {
      return parse_osc(bv)
    }
    // ESC P plus a capability reply status starts a DCS reply; bare ESC P
    // remains available for the Alt+P key path below.
    if b1 == 0x50 &&
      n > 4 &&
      (bv[2].to_int() == 0x30 || bv[2].to_int() == 0x31) &&
      bv[3].to_int() == 0x2B &&
      (bv[4].to_int() == 0x71 || bv[4].to_int() == 0x72) {
      return parse_dcs(bv)
    }
    // ESC ESC → treat first ESC as standalone escape key
    if b1 == 0x1B {
      return Ok(Key(Special("escape")), 1)
    }
    // ESC  → Alt+key
    if b1 >= 0x20 && b1 <= 0x7E {
      let ch = b1.unsafe_to_char()
      return Ok(Key(Modified("alt", String::make(1, ch))), 2)
    }
    // ESC followed by anything else → standalone escape, leave the rest
    return Ok(Key(Special("escape")), 1)
  }
  // Ctrl+letter: 0x01 (Ctrl+A) … 0x1A (Ctrl+Z)
  if b0 >= 0x01 && b0 <= 0x1A {
    let letter = (b0 + 0x60).unsafe_to_char()
    return Ok(Key(Modified("ctrl", String::make(1, letter))), 1)
  }
  // Everything else is returned as an unknown single byte.
  Ok(Unknown(Bytes::from_array([bv[0]])), 1)
}

///|
/// Drain all complete `InputEvent`s from `bv`.
///
/// Returns a tuple of the parsed events and any leftover bytes that formed an
/// incomplete sequence at the end of the buffer.
pub fn parse_all(bv : BytesView) -> (Array[InputEvent], Bytes) {
  let events : Array[InputEvent] = []
  let mut offset = 0
  let total = bv.length()
  while offset < total {
    let slice = bv[offset:total]
    match parse_input(slice) {
      Ok(evt, consumed) => {
        events.push(evt)
        offset = offset + consumed
      }
      Incomplete => break
      Invalid(_) =>
        // Skip one byte on a definitive error to avoid spinning.
        offset = offset + 1
    }
  }
  (events, Bytes::from_array(bv[offset:total].to_array()))
}