///|
/// Range unit. `Other` keeps an unknown unit without inferring semantics.
pub(all) enum RangeUnit {
  Bytes
  Other(String)
} derive(Eq, Debug)

///|
/// One syntactically valid byte-range-spec or suffix-byte-range-spec.
pub(all) enum ByteRangeSpec {
  Closed(Int64, Int64)
  OpenEnded(Int64)
  Suffix(Int64)
} derive(Eq, Debug)

///|
/// Parsed Range field. Byte units carry structured specs; other units keep raw data.
pub struct RangeRequest {
  unit : RangeUnit
  specs : Array[ByteRangeSpec]
  raw_other_range_set : String?
} derive(Eq, Debug)

///|
/// Inclusive concrete byte interval `[first, last]`.
pub struct ConcreteRange {
  first : Int64
  last : Int64
} derive(Eq, Debug)

///|
/// Resolution preserves how many original members could not be satisfied.
pub struct ResolvedRangeSet {
  satisfiable_ranges : Array[ConcreteRange]
  unsatisfiable_count : Int
  original_count : Int
} derive(Eq, Debug)

///|
pub fn range_request(
  unit : RangeUnit,
  specs : Array[ByteRangeSpec],
  raw_other_range_set? : String,
) -> RangeRequest {
  { unit, specs, raw_other_range_set }
}

///|
pub fn concrete_range(first : Int64, last : Int64) -> ConcreteRange {
  { first, last }
}

///|
pub fn resolved_range_set(
  ranges : Array[ConcreteRange],
  unsatisfiable_count : Int,
  original_count : Int,
) -> ResolvedRangeSet {
  { satisfiable_ranges: ranges, unsatisfiable_count, original_count }
}

///|
pub fn RangeUnit::name(self : RangeUnit) -> String {
  match self {
    Bytes => "bytes"
    Other(value) => value
  }
}

///|
pub fn RangeUnit::is_bytes(self : RangeUnit) -> Bool {
  self is Bytes
}

///|
pub fn RangeRequest::unit(self : RangeRequest) -> RangeUnit {
  self.unit
}

///|
pub fn RangeRequest::specs(self : RangeRequest) -> Array[ByteRangeSpec] {
  self.specs.copy()
}

///|
pub fn RangeRequest::raw_other_range_set(self : RangeRequest) -> String? {
  self.raw_other_range_set
}

///|
pub fn ConcreteRange::first(self : ConcreteRange) -> Int64 {
  self.first
}

///|
pub fn ConcreteRange::last(self : ConcreteRange) -> Int64 {
  self.last
}

///|
pub fn ConcreteRange::length(self : ConcreteRange) -> Int64 {
  self.last - self.first + 1L
}

///|
pub fn ResolvedRangeSet::ranges(
  self : ResolvedRangeSet,
) -> Array[ConcreteRange] {
  self.satisfiable_ranges.copy()
}

///|
pub fn ResolvedRangeSet::unsatisfiable_count(self : ResolvedRangeSet) -> Int {
  self.unsatisfiable_count
}

///|
pub fn ResolvedRangeSet::original_count(self : ResolvedRangeSet) -> Int {
  self.original_count
}

///|
pub fn ResolvedRangeSet::satisfiable_count(self : ResolvedRangeSet) -> Int {
  self.satisfiable_ranges.length()
}

///|
pub fn library_version() -> String {
  "0.1.0-dev"
}