///|
/// Exact JSON numeric identity and wire spelling, including fractional tokens.
/// This is not an arithmetic API; conversion to Double is explicitly lossy.
pub struct JsonNumber {
  wire : Json
  canonical : String
} derive(Debug)

///|
pub fn JsonNumber::from_json(value : Json) -> JsonNumber raise MCPError {
  guard value is Number(number, repr~) else {
    raise InvalidParams("Expected a JSON number")
  }
  let literal = match repr {
    Some(literal) => literal
    None => {
      guard !number.is_nan() && !number.is_inf() else {
        raise InvalidParams("Non-finite number has no JSON literal")
      }
      value.stringify()
    }
  }
  guard integer_key(literal, integer_only=false) is Some(canonical) else {
    raise InvalidParams("Invalid JSON number literal")
  }
  let decoded = @json.parse(literal) catch {
    _ => raise InvalidParams("Invalid JSON number representation")
  }
  guard decoded is Number(expected, ..) &&
    !number.is_nan() &&
    expected == number else {
    raise InvalidParams(
      "JSON number representation contradicts its numeric value",
    )
  }
  { wire: Json::number(number, repr=literal), canonical, }
}

///|
pub fn JsonNumber::from_literal(literal : String) -> JsonNumber raise MCPError {
  let parsed = @json.parse(literal) catch {
    _ => raise InvalidParams("Invalid JSON number literal")
  }
  guard parsed is Number(number, ..) else {
    raise InvalidParams("Expected a JSON number literal")
  }
  JsonNumber::from_json(Json::number(number, repr=literal))
}

///|
pub fn JsonNumber::to_json(self : JsonNumber) -> Json {
  self.wire
}

///|
pub fn JsonNumber::key(self : JsonNumber) -> String {
  self.canonical
}

///|
pub impl Eq for JsonNumber with fn equal(self, other) {
  self.canonical == other.canonical
}

///|
pub extend JsonNumber with Eq::{equal, not_equal}

///|
pub extend JsonNumber with @moonbitlang/core/debug.Debug::{to_repr}