///|
/// 从 JSON 值中提取字符串,不存在时使用默认值
fn get_string_opt(obj : Map[String, Json], key : String) -> String? {
  match obj.get(key) {
    Some(Json::String(s)) => Some(s)
    _ => None
  }
}

///|
/// 从 JSON 值中提取必需字符串字段
fn get_string(obj : Map[String, Json], key : String) -> String raise ParseError {
  match obj.get(key) {
    Some(Json::String(s)) => s
    None => raise ParseError::MissingField(field=key)
    _ => raise ParseError::InvalidFieldType(field=key, expected="string")
  }
}

///|
/// 从 JSON 值中提取整数字段
fn get_int(obj : Map[String, Json], key : String) -> Int raise ParseError {
  match obj.get(key) {
    Some(Json::Number(n, ..)) => n.to_int()
    None => raise ParseError::MissingField(field=key)
    _ => raise ParseError::InvalidFieldType(field=key, expected="number")
  }
}

///|
/// 从 JSON 值中提取可选整数字段
fn get_int_opt(obj : Map[String, Json], key : String) -> Int? raise ParseError {
  match obj.get(key) {
    Some(Json::Number(n, ..)) => Some(n.to_int())
    None => None
    _ => raise ParseError::InvalidFieldType(field=key, expected="number")
  }
}

///|
/// 从 JSON 值中提取浮点数字段
fn get_double(
  obj : Map[String, Json],
  key : String,
  default~ : Double,
) -> Double raise ParseError {
  match obj.get(key) {
    Some(Json::Number(n, ..)) => n
    None => default
    _ => raise ParseError::InvalidFieldType(field=key, expected="number")
  }
}

///|
/// 从 JSON 值中提取布尔字段
fn get_bool(
  obj : Map[String, Json],
  key : String,
  default~ : Bool,
) -> Bool raise ParseError {
  match obj.get(key) {
    Some(Json::True) => true
    Some(Json::False) => false
    None => default
    _ => raise ParseError::InvalidFieldType(field=key, expected="boolean")
  }
}

///|
/// 从 JSON 值中提取数值数组
fn get_number_array(
  obj : Map[String, Json],
  key : String,
) -> Array[Double] raise ParseError {
  match obj.get(key) {
    Some(Json::Array(arr)) => {
      let result = []
      for item in arr {
        match item {
          Json::Number(n, ..) => result.push(n)
          _ =>
            raise ParseError::InvalidFieldType(
              field=key,
              expected="array of numbers",
            )
        }
      }
      result
    }
    None => []
    _ => raise ParseError::InvalidFieldType(field=key, expected="array")
  }
}

///|
/// 从 JSON 值中提取对象数组
fn get_obj_array(
  obj : Map[String, Json],
  key : String,
) -> Array[Map[String, Json]] raise ParseError {
  match obj.get(key) {
    Some(Json::Array(arr)) => {
      let result = []
      for item in arr {
        match item {
          Json::Object(o) => result.push(o)
          _ =>
            raise ParseError::InvalidFieldType(
              field=key,
              expected="array of objects",
            )
        }
      }
      result
    }
    None => []
    _ => raise ParseError::InvalidFieldType(field=key, expected="array")
  }
}

///|
/// 从 JSON 值中提取整数数组
fn get_int_array(
  obj : Map[String, Json],
  key : String,
) -> Array[Int] raise ParseError {
  match obj.get(key) {
    Some(Json::Array(arr)) => {
      let result = []
      for item in arr {
        match item {
          Json::Number(n, ..) => result.push(n.to_int())
          _ =>
            raise ParseError::InvalidFieldType(
              field=key,
              expected="array of integers",
            )
        }
      }
      result
    }
    None => []
    _ => raise ParseError::InvalidFieldType(field=key, expected="array")
  }
}

// ===== 枚举解析辅助 =====

///|
fn parse_accessor_type(s : String) -> AccessorType raise ParseError {
  match s {
    "SCALAR" => Scalar
    "VEC2" => Vec2
    "VEC3" => Vec3
    "VEC4" => Vec4
    "MAT2" => Mat2
    "MAT3" => Mat3
    "MAT4" => Mat4
    _ => raise ParseError::UnknownEnum(field="type", value=s)
  }
}

///|
fn parse_component_type(code : Int) -> ComponentType raise ParseError {
  match code {
    5120 => Byte
    5121 => UnsignedByte
    5122 => Short
    5123 => UnsignedShort
    5125 => UnsignedInt
    5126 => Float
    _ => raise ParseError::UnknownEnum(field="componentType", value="\{code}")
  }
}

///|
fn parse_alpha_mode(s : String) -> AlphaMode raise ParseError {
  match s {
    "OPAQUE" => Opaque
    "MASK" => Mask
    "BLEND" => Blend
    _ => raise ParseError::UnknownEnum(field="alphaMode", value=s)
  }
}

///|
fn parse_primitive_mode(code : Int) -> PrimitiveMode raise ParseError {
  match code {
    0 => Points
    1 => Lines
    2 => LineLoop
    3 => LineStrip
    4 => Triangles
    5 => TriangleStrip
    6 => TriangleFan
    _ => raise ParseError::UnknownEnum(field="mode", value="\{code}")
  }
}

///|
fn parse_interpolation(s : String) -> Interpolation raise ParseError {
  match s {
    "LINEAR" => Linear
    "STEP" => Step
    "CUBICSPLINE" => CubicSpline
    _ => raise ParseError::UnknownEnum(field="interpolation", value=s)
  }
}

///|
fn parse_animation_path(s : String) -> AnimationPath raise ParseError {
  match s {
    "translation" => Translation
    "rotation" => Rotation
    "scale" => Scale
    "weights" => Weights
    _ => raise ParseError::UnknownEnum(field="path", value=s)
  }
}

///|
fn parse_filter_mode(code : Int) -> FilterMode raise ParseError {
  match code {
    9728 => Nearest
    9729 => Linear
    9984 => NearestMipmapNearest
    9985 => LinearMipmapNearest
    9986 => NearestMipmapLinear
    9987 => LinearMipmapLinear
    _ => raise ParseError::UnknownEnum(field="filter", value="\{code}")
  }
}

///|
fn parse_wrap_mode(code : Int) -> WrapMode raise ParseError {
  match code {
    33071 => ClampToEdge
    33648 => MirroredRepeat
    10497 => Repeat
    _ => raise ParseError::UnknownEnum(field="wrap", value="\{code}")
  }
}

// ===== 子结构解析 =====

///|
fn parse_vec3(arr : Array[Json]) -> Vec3 raise ParseError {
  if arr.length() < 3 {
    raise ParseError::OutOfRange(msg="Vec3 requires 3 components")
  }
  let x = match arr[0] {
    Json::Number(n, ..) => n
    _ => raise ParseError::InvalidFieldType(field="vec3[0]", expected="number")
  }
  let y = match arr[1] {
    Json::Number(n, ..) => n
    _ => raise ParseError::InvalidFieldType(field="vec3[1]", expected="number")
  }
  let z = match arr[2] {
    Json::Number(n, ..) => n
    _ => raise ParseError::InvalidFieldType(field="vec3[2]", expected="number")
  }
  { x, y, z }
}

///|
fn parse_quat(arr : Array[Json]) -> Quat raise ParseError {
  if arr.length() < 4 {
    raise ParseError::OutOfRange(msg="Quat requires 4 components")
  }
  let x = match arr[0] {
    Json::Number(n, ..) => n
    _ => raise ParseError::InvalidFieldType(field="quat[0]", expected="number")
  }
  let y = match arr[1] {
    Json::Number(n, ..) => n
    _ => raise ParseError::InvalidFieldType(field="quat[1]", expected="number")
  }
  let z = match arr[2] {
    Json::Number(n, ..) => n
    _ => raise ParseError::InvalidFieldType(field="quat[2]", expected="number")
  }
  let w = match arr[3] {
    Json::Number(n, ..) => n
    _ => raise ParseError::InvalidFieldType(field="quat[3]", expected="number")
  }
  { x, y, z, w }
}

///|
fn parse_color4(
  arr : Array[Json],
  default_alpha? : Double = 1.0,
) -> Color4 raise ParseError {
  if arr.length() < 3 {
    raise ParseError::OutOfRange(msg="Color requires at least 3 components")
  }
  let r = match arr[0] {
    Json::Number(n, ..) => n
    _ => raise ParseError::InvalidFieldType(field="color[0]", expected="number")
  }
  let g = match arr[1] {
    Json::Number(n, ..) => n
    _ => raise ParseError::InvalidFieldType(field="color[1]", expected="number")
  }
  let b = match arr[2] {
    Json::Number(n, ..) => n
    _ => raise ParseError::InvalidFieldType(field="color[2]", expected="number")
  }
  let a = if arr.length() >= 4 {
    match arr[3] {
      Json::Number(n, ..) => n
      _ =>
        raise ParseError::InvalidFieldType(field="color[3]", expected="number")
    }
  } else {
    default_alpha
  }
  { r, g, b, a }
}

///|
fn parse_texture_info(obj : Map[String, Json]) -> TextureInfo raise ParseError {
  let index = get_int(obj, "index")
  let tex_coord = match get_int_opt(obj, "texCoord") {
    Some(n) => n
    None => 0
  }
  { index, tex_coord }
}

///|
fn parse_pbr(obj : Map[String, Json]) -> PbrMetallicRoughness raise ParseError {
  let base_color_factor = match obj.get("baseColorFactor") {
    Some(Json::Array(arr)) => parse_color4(arr)
    None => { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }
    _ =>
      raise ParseError::InvalidFieldType(
        field="baseColorFactor",
        expected="array",
      )
  }
  let base_color_texture = match obj.get("baseColorTexture") {
    Some(Json::Object(o)) => Some(parse_texture_info(o))
    _ => None
  }
  let metallic_factor = get_double(obj, "metallicFactor", default=1.0)
  let roughness_factor = get_double(obj, "roughnessFactor", default=1.0)
  let metallic_roughness_texture = match obj.get("metallicRoughnessTexture") {
    Some(Json::Object(o)) => Some(parse_texture_info(o))
    _ => None
  }
  {
    base_color_factor,
    base_color_texture,
    metallic_factor,
    roughness_factor,
    metallic_roughness_texture,
  }
}