///|
/// Default offline budgets: 8 MiB input, 100,000 segments, 64 KiB per segment,
/// 1,024 elements per segment, 128 components per element, 100 diagnostics.
pub fn default_limits() -> ParseLimits {
  {
    max_input_bytes: 8388608,
    max_segments: 100000,
    max_segment_bytes: 65536,
    max_elements: 1024,
    max_components: 128,
    max_diagnostics: 100,
  }
}

///|
/// Parse bytes under explicit limits. No I/O, time, network or implicit decoding.
pub fn parse(
  input : Bytes,
  limits? : ParseLimits = default_limits(),
) -> ParseResult {
  if limits.max_input_bytes <= 0 ||
    limits.max_segments <= 0 ||
    limits.max_segment_bytes <= 0 ||
    limits.max_elements <= 0 ||
    limits.max_components <= 0 ||
    limits.max_diagnostics <= 0 {
    return parse_failure(
      diagnostic(
        "R_LIMITS_INVALID",
        Resource,
        0,
        0,
        "All resource limits must be positive.",
      ),
    )
  }
  if input.length() > limits.max_input_bytes {
    return parse_failure(
      diagnostic(
        "R_INPUT_BYTES",
        Resource,
        0,
        input.length(),
        "Input exceeds the configured byte budget.",
      ),
    )
  }
  let profile = match detect_syntax(input) {
    Ok(profile) => profile
    Err(error) => return parse_failure(error)
  }
  let segments : Array[Segment] = []
  let mut pos = profile.body_start
  while pos < input.length() {
    if input[pos] == b'\r' || input[pos] == b'\n' {
      pos = pos + 1
      continue
    }
    if segments.length() >= limits.max_segments {
      return parse_failure(
        diagnostic(
          "R_SEGMENTS",
          Resource,
          pos,
          pos + (input.length() - pos).min(3),
          "Segment count exceeds the configured budget.",
          segment_index=segments.length() + 1,
        ),
      )
    }
    match scan_segment(input, pos, profile, limits, segments.length() + 1) {
      Err(error) => return parse_failure(error)
      Ok((segment, next)) => {
        segments.push(segment)
        pos = next
      }
    }
  }
  let end = if segments.is_empty() {
    profile.body_start
  } else {
    segments[segments.length() - 1].span.end
  }
  let document : Document = {
    profile,
    segments,
    span: { start: profile.body_start, end, },
  }
  let envelope = validate_envelope(
    document,
    max_diagnostics=limits.max_diagnostics,
  )
  {
    document: Some(document),
    interchange: envelope.interchange,
    diagnostics: envelope.diagnostics,
    syntax: Passed,
    envelope: envelope.status,
    rules: NotChecked,
  }
}

///|
fn parse_failure(error : Diagnostic) -> ParseResult {
  {
    document: None,
    interchange: None,
    diagnostics: [error],
    syntax: Failed,
    envelope: NotChecked,
    rules: NotChecked,
  }
}