///|
/// Processing stage for a structured range error.
pub(all) enum RangeErrorStage {
  Input
  Unit
  Syntax
  Number
  RangeSpec
  ContentRange
  AcceptRanges
  Resolve
  Limit
  Plan
} derive(Eq, Debug)

///|
/// Machine-readable error category.
pub(all) enum RangeErrorKind {
  EmptyInput
  MissingEquals
  InvalidUnit
  EmptyRangeSet
  InvalidRange
  MissingNumber
  InvalidNumber
  IntegerOverflow
  LastBeforeFirst
  InvalidCompleteLength
  LimitExceeded
  UnexpectedCharacter
  InvalidRepresentationLength
  UnsupportedRangeUnit
  InvalidBoundary
} derive(Eq, Debug)

///|
/// Offset is a zero-based MoonBit string code-unit offset, not a UTF-8 byte offset.
pub(all) suberror RangeError {
  RangeError(RangeErrorStage, RangeErrorKind, Int, String)
}

///|
pub fn range_error(
  stage : RangeErrorStage,
  kind : RangeErrorKind,
  offset : Int,
  context : String,
) -> RangeError {
  RangeError(stage, kind, offset, context)
}

///|
pub fn RangeError::stage(self : RangeError) -> RangeErrorStage {
  match self {
    RangeError(stage, _, _, _) => stage
  }
}

///|
pub fn RangeError::kind(self : RangeError) -> RangeErrorKind {
  match self {
    RangeError(_, kind, _, _) => kind
  }
}

///|
pub fn RangeError::offset(self : RangeError) -> Int {
  match self {
    RangeError(_, _, offset, _) => offset
  }
}

///|
pub fn RangeError::context(self : RangeError) -> String {
  match self {
    RangeError(_, _, _, context) => context
  }
}

///|
pub fn RangeErrorStage::name(self : RangeErrorStage) -> String {
  match self {
    Input => "Input"
    Unit => "Unit"
    Syntax => "Syntax"
    Number => "Number"
    RangeSpec => "RangeSpec"
    ContentRange => "ContentRange"
    AcceptRanges => "AcceptRanges"
    Resolve => "Resolve"
    Limit => "Limit"
    Plan => "Plan"
  }
}

///|
pub fn RangeErrorKind::name(self : RangeErrorKind) -> String {
  match self {
    EmptyInput => "EmptyInput"
    MissingEquals => "MissingEquals"
    InvalidUnit => "InvalidUnit"
    EmptyRangeSet => "EmptyRangeSet"
    InvalidRange => "InvalidRange"
    MissingNumber => "MissingNumber"
    InvalidNumber => "InvalidNumber"
    IntegerOverflow => "IntegerOverflow"
    LastBeforeFirst => "LastBeforeFirst"
    InvalidCompleteLength => "InvalidCompleteLength"
    LimitExceeded => "LimitExceeded"
    UnexpectedCharacter => "UnexpectedCharacter"
    InvalidRepresentationLength => "InvalidRepresentationLength"
    UnsupportedRangeUnit => "UnsupportedRangeUnit"
    InvalidBoundary => "InvalidBoundary"
  }
}

///|
pub fn RangeError::to_string(self : RangeError) -> String {
  "\{self.stage().name()}/\{self.kind().name()} at \{self.offset()}: \{self.context()}"
}

///|
fn unwrap_range_error(error : Error) -> RangeError {
  match error {
    RangeError(stage, kind, offset, context) =>
      RangeError(stage, kind, offset, context)
    _ => abort("internal error: unexpected error type")
  }
}