///|
/// 转换信封 JSON 编解码 — ConversionStatus / ConversionDiagnostic / ConversionResult
///
/// 让 Exact/Degraded/Unsupported/Invalid 成为可检测的协议输出。
/// JSON 形状:
///   ConversionStatus:    "exact" | "degraded" | "unsupported" | "invalid"
///   ConversionDiagnostic: {"field":"...","status":"...","detail":"..."}
///   ConversionResult:     {"value":,"diagnostics":[...]}
///   envelope_json:        {"value":,"diagnostics":[...]}

///|
/// === ConversionStatus ===

///|
pub fn ConversionStatus::to_json(self : ConversionStatus) -> Json {
  match self {
    Exact => Json::string("exact")
    Degraded => Json::string("degraded")
    Unsupported => Json::string("unsupported")
    Invalid => Json::string("invalid")
  }
}

///|
pub fn ConversionStatus::from_json(
  jv : Json,
) -> Result[ConversionStatus, String] {
  match jv {
    String(s) =>
      match s {
        "exact" => Ok(Exact)
        "degraded" => Ok(Degraded)
        "unsupported" => Ok(Unsupported)
        "invalid" => Ok(Invalid)
        _ => Err("unknown ConversionStatus: " + s)
      }
    _ => Err("expected string for ConversionStatus")
  }
}

///|
/// === ConversionDiagnostic ===

///|
pub fn ConversionDiagnostic::to_json(self : ConversionDiagnostic) -> Json {
  let fields : Map[String, Json] = {
    "field": Json::string(self.field),
    "status": self.status.to_json(),
  }
  match self.detail {
    Some(d) => fields.set("detail", Json::string(d))
    None => ()
  }
  Json::object(fields)
}

///|
pub fn ConversionDiagnostic::from_json(
  jv : Json,
) -> Result[ConversionDiagnostic, String] {
  match jv {
    Object(map) => {
      let field = match map.get("field") {
        Some(String(s)) => s
        _ => return Err("missing or invalid field for ConversionDiagnostic")
      }
      let status = match map.get("status") {
        Some(v) =>
          match ConversionStatus::from_json(v) {
            Ok(s) => s
            Err(e) => return Err(e)
          }
        None => return Err("missing status for ConversionDiagnostic")
      }
      let detail = match map.get("detail") {
        Some(String(s)) => Some(s)
        _ => None
      }
      Ok(ConversionDiagnostic::new(field, status, detail))
    }
    _ => Err("expected object for ConversionDiagnostic")
  }
}

///|
/// === ConversionResult ===

///|
/// 序列化:value 由调用方提供编码函数,diagnostics 统一编码。
pub fn[T] ConversionResult::to_json(
  self : ConversionResult[T],
  encode : (T) -> Json,
) -> Json {
  let diags : Array[Json] = self.diagnostics.map(fn(d) { d.to_json() })
  let fields : Map[String, Json] = {
    "value": encode(self.value),
    "diagnostics": Json::array(diags),
  }
  Json::object(fields)
}

///|
/// 反序列化:value 由调用方提供解码函数。
pub fn[T] ConversionResult::from_json(
  jv : Json,
  decode : (Json) -> Result[T, String],
) -> Result[ConversionResult[T], String] {
  match jv {
    Object(map) => {
      let value = match map.get("value") {
        Some(v) =>
          match decode(v) {
            Ok(t) => t
            Err(e) => return Err("value decode failed: " + e)
          }
        None => return Err("missing value for ConversionResult")
      }
      let mut result = ConversionResult::new(value)
      match map.get("diagnostics") {
        Some(Array(arr)) =>
          for item in arr {
            match ConversionDiagnostic::from_json(item) {
              Ok(d) => result = result.with_diagnostic(d)
              Err(e) => return Err("diagnostic decode failed: " + e)
            }
          }
        _ => ()
      }
      Ok(result)
    }
    _ => Err("expected object for ConversionResult")
  }
}

///|
/// 信封 JSON:`{"value":,"diagnostics":[...]}`(WASM/SDK 边界用)。
pub fn[T] ConversionResult::envelope_json(
  self : ConversionResult[T],
  value_json : Json,
) -> Json {
  let diags : Array[Json] = self.diagnostics.map(fn(d) { d.to_json() })
  let fields : Map[String, Json] = {
    "value": value_json,
    "diagnostics": Json::array(diags),
  }
  Json::object(fields)
}