///|
/// 服务端返回的业务错误:HTTP 响应已经到达,但信封里的 `code` 不是 200。
///
/// OpenList 用 `code` 表达业务结果,HTTP 状态码只是它的粗粒度映射,
/// 所以两边都保留:`code`/`message` 来自信封,`status` 来自 HTTP 状态行。
pub struct ApiError {
  /// 业务错误码(信封里的 `code`)。
  code : Int
  /// 业务错误消息(信封里的 `message`)。
  message : String
  /// HTTP 状态码。
  status : Int
  /// 错误响应携带的 `data`;字段缺失或为 `null` 时是 `None`。
  data : Json?
} derive(@debug.Debug)

///|
/// 显式声明 `derive` 出来的 `Debug` 实现以普通方法暴露,避免工具链的
/// 「隐式提升为方法」弃用告警(行为与 `derive` 完全一致)。
pub extend ApiError with @debug.Debug::{to_repr}

///|
/// 客户端可能抛出的全部错误。
pub(all) suberror OpenListError {
  /// 传输层错误:连接失败、超时、取消、非法 URL 等(原样保留 moonhttp 的错误)。
  Http(@moonhttp.HttpError)
  /// 业务错误:服务端信封里的 `code` 不是 200。
  Api(ApiError)
  /// 协议错误:响应不是 JSON 信封,或 `data` 无法解码成目标类型。
  Decode(String)
}

///|
/// 人类可读的一行错误消息,适合直接写日志。
pub fn OpenListError::message(self : OpenListError) -> String {
  match self {
    Http(error) => "HTTP: \{error.message()}"
    Api(error) => "API \{error.code}: \{error.message}"
    Decode(message) => "Decode: \{message}"
  }
}

///|
/// 对应的 HTTP 状态码;传输层没拿到响应时是 `None`。
pub fn OpenListError::status(self : OpenListError) -> Int? {
  match self {
    Http(error) =>
      match error.response() {
        Some(response) => Some(response.status)
        None => None
      }
    Api(error) => Some(error.status)
    Decode(_) => None
  }
}

///|
/// 业务错误码;不是 `Api` 错误时是 `None`。
pub fn OpenListError::code(self : OpenListError) -> Int? {
  match self {
    Api(error) => Some(error.code)
    _ => None
  }
}