///|
/// Range header parsing errors (RFC 9110)
pub(all) enum RangeError {
  Empty
  InvalidFormat
  InvalidUnit
  InvalidRange
  InvalidBounds
} derive(Show, Eq)

///|
/// Range specification (RFC 9110 Section 14.2)
pub(all) enum RangeSpec {
  /// Range from start to end (inclusive)
  /// bytes=0-499 -> Range { start: 0UL, end: 499UL }
  Range(UInt64, UInt64)
  /// Range from start to end of resource
  /// bytes=500- -> FromStart { start: 500UL }
  FromStart(UInt64)
  /// Last n bytes
  /// bytes=-500 -> Suffix { length: 500UL }
  Suffix(UInt64)
} derive(Eq)

///|
pub fn RangeSpec::to_bounds(
  self : RangeSpec,
  total_length : UInt64,
) -> (UInt64, UInt64)? {
  if total_length == 0UL {
    return None
  }
  match self {
    Range(s, e) => {
      if s > e || s >= total_length {
        return None
      }
      let end = if e < total_length { e } else { total_length - 1UL }
      Some((s, end))
    }
    FromStart(s) => {
      if s >= total_length {
        return None
      }
      Some((s, total_length - 1UL))
    }
    Suffix(l) => {
      if l == 0UL {
        return None
      }
      let start = if total_length > l { total_length - l } else { 0UL }
      Some((start, total_length - 1UL))
    }
  }
}

///|
pub fn RangeSpec::to_string(self : RangeSpec) -> String {
  match self {
    Range(s, e) => rg_u64_to_string(s) + "-" + rg_u64_to_string(e)
    FromStart(s) => rg_u64_to_string(s) + "-"
    Suffix(l) => "-" + rg_u64_to_string(l)
  }
}

///|
/// Range header (RFC 9110 Section 14.2)
pub(all) struct Range {
  unit : String
  ranges : Array[RangeSpec]
} derive(Eq)

///|
pub fn Range::parse(input : String) -> Result[Range, RangeError] {
  let s = input
  if s.length() == 0 {
    return Err(Empty)
  }

  // Check for "bytes=" prefix
  if s.length() < 6 {
    return Err(InvalidFormat)
  }

  // Simple check: does string start with "bytes="
  let mut has_bytes = true
  if s[0] != 'b' {
    has_bytes = false
  } else if s[1] != 'y' {
    has_bytes = false
  } else if s[2] != 't' {
    has_bytes = false
  } else if s[3] != 'e' {
    has_bytes = false
  } else if s[4] != 's' {
    has_bytes = false
  } else if s[5] != '=' {
    has_bytes = false
  }
  if !has_bytes {
    return Err(InvalidFormat)
  }

  // Parse everything after "bytes="
  let ranges_str = rg_string_slice_from(s, 6)
  let parts = rg_split_string(ranges_str, ",")
  let ranges : Array[RangeSpec] = []
  let mut idx = 0
  while idx < parts.length() {
    let part = rg_trim_string(parts[idx])
    if part.length() > 0 {
      match rg_parse_range_spec(part) {
        Ok(spec) => ranges.push(spec)
        Err(e) => return Err(e)
      }
    }
    idx = idx + 1
  }
  if ranges.length() == 0 {
    return Err(Empty)
  }
  Ok({ unit: "bytes", ranges })
}

///|
pub fn Range::unit(self : Range) -> String {
  self.unit
}

///|
pub fn Range::is_bytes(self : Range) -> Bool {
  rg_to_lower_case(self.unit) == "bytes"
}

///|
pub fn Range::ranges(self : Range) -> Array[RangeSpec] {
  self.ranges
}

///|
pub fn Range::first(self : Range) -> RangeSpec? {
  if self.ranges.length() > 0 {
    Some(self.ranges[0])
  } else {
    None
  }
}

///|
pub fn Range::to_string(self : Range) -> String {
  let mut result = self.unit + "="
  let mut idx = 0
  while idx < self.ranges.length() {
    if idx > 0 {
      result = result + ", "
    }
    result = result + self.ranges[idx].to_string()
    idx = idx + 1
  }
  result
}

///|
/// Content-Range header (RFC 9110 Section 14.4)
pub(all) struct ContentRange {
  unit : String
  start : UInt64?
  end : UInt64?
  complete_length : UInt64?
} derive(Eq)

///|
pub fn ContentRange::parse(input : String) -> Result[ContentRange, RangeError] {
  let s = rg_trim_string(input)
  if s.length() == 0 {
    return Err(Empty)
  }

  // Find space for "unit range/length" format
  let space_pos = rg_find_char(s, 32)
  match space_pos {
    None => Err(InvalidFormat)
    Some(pos) => {
      let unit = rg_trim_string(rg_string_slice(s, 0, pos))
      let rest = rg_trim_string(rg_string_slice_from(s, pos + 1))
      if unit.length() == 0 {
        return Err(InvalidUnit)
      }

      // Find '/' for "range/length"
      let slash_pos = rg_find_char(rest, 47)
      match slash_pos {
        None => Err(InvalidFormat)
        Some(spos) => {
          let range_str = rg_trim_string(rg_string_slice(rest, 0, spos))
          let length_str = rg_trim_string(rg_string_slice_from(rest, spos + 1))
          let complete_length : UInt64? = if length_str == "*" {
            None
          } else {
            match rg_parse_u64(length_str) {
              Some(len) => Some(len)
              None => return Err(InvalidFormat)
            }
          }
          if range_str == "*" {
            // unsatisfied range: bytes */1000
            return Ok({ unit, start: None, end: None, complete_length })
          }

          // Parse start-end
          let dash_pos = rg_find_char(range_str, 45)
          match dash_pos {
            None => Err(InvalidFormat)
            Some(dpos) => {
              let start_str = rg_string_slice(range_str, 0, dpos)
              let end_str = rg_string_slice_from(range_str, dpos + 1)
              match (rg_parse_u64(start_str), rg_parse_u64(end_str)) {
                (Some(s), Some(e)) => {
                  if s > e {
                    return Err(InvalidBounds)
                  }
                  Ok({ unit, start: Some(s), end: Some(e), complete_length })
                }
                _ => Err(InvalidFormat)
              }
            }
          }
        }
      }
    }
  }
}

///|
pub fn ContentRange::new_bytes(
  start : UInt64,
  end : UInt64,
  complete_length : UInt64?,
) -> ContentRange {
  { unit: "bytes", start: Some(start), end: Some(end), complete_length }
}

///|
pub fn ContentRange::unsatisfied(
  unit : String,
  complete_length : UInt64,
) -> ContentRange {
  { unit, start: None, end: None, complete_length: Some(complete_length) }
}

///|
pub fn ContentRange::unit(self : ContentRange) -> String {
  self.unit
}

///|
pub fn ContentRange::start(self : ContentRange) -> UInt64? {
  self.start
}

///|
pub fn ContentRange::end(self : ContentRange) -> UInt64? {
  self.end
}

///|
pub fn ContentRange::complete_length(self : ContentRange) -> UInt64? {
  self.complete_length
}

///|
pub fn ContentRange::length(self : ContentRange) -> UInt64? {
  match (self.start, self.end) {
    (Some(s), Some(e)) => if e >= s { Some(e - s + 1UL) } else { None }
    _ => None
  }
}

///|
pub fn ContentRange::is_unsatisfied(self : ContentRange) -> Bool {
  match (self.start, self.end) {
    (None, None) => true
    _ => false
  }
}

///|
pub fn ContentRange::to_string(self : ContentRange) -> String {
  let mut result = self.unit + " "
  match (self.start, self.end) {
    (Some(s), Some(e)) =>
      result = result + rg_u64_to_string(s) + "-" + rg_u64_to_string(e) + "/"
    _ => result = result + "*/"
  }
  match self.complete_length {
    Some(len) => result + rg_u64_to_string(len)
    None => result + "*"
  }
}

///|
/// Accept-Ranges header (RFC 9110 Section 14.3)
pub(all) struct AcceptRanges {
  units : Array[String]
} derive(Eq)

///|
pub fn AcceptRanges::parse(input : String) -> Result[AcceptRanges, RangeError] {
  let s = rg_trim_string(input)
  if s.length() == 0 {
    return Err(Empty)
  }
  let parts = rg_split_string(s, ",")
  let units : Array[String] = []
  let mut idx = 0
  while idx < parts.length() {
    let unit = rg_trim_string(parts[idx])
    if unit.length() > 0 {
      units.push(unit)
    }
    idx = idx + 1
  }
  if units.length() == 0 {
    return Err(Empty)
  }
  Ok({ units, })
}

///|
pub fn AcceptRanges::bytes() -> AcceptRanges {
  { units: ["bytes"] }
}

///|
pub fn AcceptRanges::none() -> AcceptRanges {
  { units: ["none"] }
}

///|
pub fn AcceptRanges::units(self : AcceptRanges) -> Array[String] {
  self.units
}

///|
pub fn AcceptRanges::accepts_bytes(self : AcceptRanges) -> Bool {
  let mut idx = 0
  while idx < self.units.length() {
    if rg_to_lower_case(self.units[idx]) == "bytes" {
      return true
    }
    idx = idx + 1
  }
  false
}

///|
pub fn AcceptRanges::is_none(self : AcceptRanges) -> Bool {
  if self.units.length() == 1 && rg_to_lower_case(self.units[0]) == "none" {
    true
  } else {
    false
  }
}

///|
pub fn AcceptRanges::to_string(self : AcceptRanges) -> String {
  let mut result = ""
  let mut idx = 0
  while idx < self.units.length() {
    if idx > 0 {
      result = result + ", "
    }
    result = result + self.units[idx]
    idx = idx + 1
  }
  result
}

///|

///|
/// Helper functions

///|

///|

///|
fn rg_parse_range_spec(s : String) -> Result[RangeSpec, RangeError] {
  // Find '-' manually by checking each character
  let mut dash_pos = -1
  let mut idx = 0
  while idx < s.length() {
    let ch_code = s[idx].to_int()
    if ch_code == 45 { // '-' = 45
      dash_pos = idx
      break
    }
    idx = idx + 1
  }
  if dash_pos == -1 {
    return Err(InvalidRange)
  }

  // Get start and end parts
  let mut start_str = ""
  let mut j = 0
  while j < dash_pos {
    start_str = start_str + s[j].unsafe_to_char().to_string()
    j = j + 1
  }
  let mut end_str = ""
  j = dash_pos + 1
  while j < s.length() {
    end_str = end_str + s[j].unsafe_to_char().to_string()
    j = j + 1
  }

  // Trim whitespace
  start_str = rg_trim_string(start_str)
  end_str = rg_trim_string(end_str)
  if start_str.length() == 0 && end_str.length() == 0 {
    return Err(InvalidRange)
  }
  if start_str.length() == 0 {
    // Suffix: -500
    match rg_parse_u64(end_str) {
      Some(length) => Ok(Suffix(length))
      None => Err(InvalidRange)
    }
  } else if end_str.length() == 0 {
    // FromStart: 500-
    match rg_parse_u64(start_str) {
      Some(start) => Ok(FromStart(start))
      None => Err(InvalidRange)
    }
  } else {
    // Range: 0-499
    match (rg_parse_u64(start_str), rg_parse_u64(end_str)) {
      (Some(start), Some(end)) =>
        if start > end {
          Err(InvalidBounds)
        } else {
          Ok(Range(start, end))
        }
      _ => Err(InvalidRange)
    }
  }
}

///|
fn rg_trim_string(s : String) -> String {
  str_trim_string(s)
}

///|
fn rg_char_at(s : String, idx : Int) -> Int {
  str_char_at(s, idx)
}

///|
fn rg_string_slice(s : String, start : Int, end : Int) -> String {
  str_string_slice(s, start, end)
}

///|
fn rg_string_slice_from(s : String, start : Int) -> String {
  str_string_slice_from(s, start)
}

///|
fn rg_find_char(s : String, target : Int) -> Int? {
  let mut idx = 0
  while idx < s.length() {
    if rg_char_at(s, idx) == target {
      return Some(idx)
    }
    idx = idx + 1
  }
  None
}

///|
fn rg_split_string(s : String, sep : String) -> Array[String] {
  str_split_string(s, sep)
}

///|
fn rg_to_lower_case(s : String) -> String {
  str_to_lower_case(s)
}

///|
pub fn rg_parse_u64(s : String) -> UInt64? {
  if s.length() == 0 {
    return None
  }
  let mut result : UInt64 = 0UL
  let mut idx = 0
  let len = s.length()
  while idx < len {
    let ch = rg_char_at(s, idx)
    if ch < 48 || ch > 57 {
      return None
    }

    // Convert digit char to UInt64 by building it up
    let digit = ch - 48 // This gives us Int 0-9
    let digit_u64 = int_digit_to_u64(digit)

    // Check for overflow before multiplying
    // We check if result > (MAX_U64 / 10)
    // MAX_U64 / 10 = 1844674407370955161
    if rg_u64_greater_than(result, 1844674407370955161UL) {
      return None
    }
    result = result * 10UL

    // Check if result > MAX_U64 - digit
    if rg_u64_greater_than(
        result,
        rg_u64_subtract(18446744073709551615UL, digit_u64),
      ) {
      return None
    }
    result = result + digit_u64
    idx = idx + 1
  }
  Some(result)
}

///|
fn int_digit_to_u64(d : Int) -> UInt64 {
  // Convert single digit Int (0-9) to UInt64
  if d == 0 {
    0UL
  } else if d == 1 {
    1UL
  } else if d == 2 {
    2UL
  } else if d == 3 {
    3UL
  } else if d == 4 {
    4UL
  } else if d == 5 {
    5UL
  } else if d == 6 {
    6UL
  } else if d == 7 {
    7UL
  } else if d == 8 {
    8UL
  } else {
    9UL
  }
}

///|
fn rg_u64_greater_than(a : UInt64, b : UInt64) -> Bool {
  a > b
}

///|
fn rg_u64_subtract(a : UInt64, b : UInt64) -> UInt64 {
  // Safe subtraction that returns 0 on underflow
  if b > a {
    0UL
  } else {
    a - b
  }
}

///|
pub fn rg_u64_to_string(n : UInt64) -> String {
  if n == 0UL {
    return "0"
  }
  let chars : Array[String] = []
  let mut num = n
  while num > 0UL {
    let remainder = num % 10UL
    // Convert UInt64 digit (0-9) to Int using subtraction
    let digit_int = u64_digit_to_int(remainder)
    chars.push(Int::unsafe_to_char(digit_int + 48).to_string())
    num = num / 10UL
  }
  let mut result = ""
  let mut idx = chars.length() - 1
  while idx >= 0 {
    result = result + chars[idx]
    if idx == 0 {
      break
    }
    idx = idx - 1
  }
  result
}

///|
fn u64_digit_to_int(d : UInt64) -> Int {
  // Convert a single digit UInt64 (0-9) to Int
  if d == 0UL {
    0
  } else if d == 1UL {
    1
  } else if d == 2UL {
    2
  } else if d == 3UL {
    3
  } else if d == 4UL {
    4
  } else if d == 5UL {
    5
  } else if d == 6UL {
    6
  } else if d == 7UL {
    7
  } else if d == 8UL {
    8
  } else {
    9
  }
}