///|
/// Metadata describing a single model available at the endpoint.
pub(all) struct Model {
  id : String
  object : String
  created : Int64
  owned_by : String
} derive(Debug)

///|
pub impl @json.FromJson for Model with fn from_json(
  json : Json,
  path : @json.JsonPath,
) -> Model {
  guard json is Object(obj) else {
    raise @json.JsonDecodeError((path, "Model: expected object"))
  }
  let id = match obj.get("id") {
    Some(String(s)) => s
    _ => ""
  }
  let object = match obj.get("object") {
    Some(String(s)) => s
    _ => "model"
  }
  let created = match obj.get("created") {
    Some(Number(n, ..)) => n.to_int64()
    _ => 0L
  }
  let owned_by = match obj.get("owned_by") {
    Some(String(s)) => s
    _ => ""
  }
  { id, object, created, owned_by }
}

///|
/// The response from the `GET /models` endpoint.
pub(all) struct ModelList {
  data : Array[Model]
} derive(Debug)

///|
pub impl @json.FromJson for ModelList with fn from_json(
  json : Json,
  path : @json.JsonPath,
) -> ModelList {
  guard json is Object(obj) else {
    raise @json.JsonDecodeError((path, "ModelList: expected object"))
  }
  let data = match obj.get("data") {
    Some(Array(_) as d) => @json.from_json(d)
    _ => []
  }
  { data, }
}

///|
/// The ids of all listed models.
pub fn ModelList::ids(self : ModelList) -> Array[String] {
  let out = []
  for m in self.data {
    out.push(m.id)
  }
  out
}

///|
/// List the models available at the endpoint (`GET /models`).
pub async fn Client::models(self : Client) -> ModelList raise LLMError {
  let json = self.get_json("/models")
  @json.from_json(json) catch {
    err => raise Decode(err.to_string())
  }
}

///|
/// Retrieve metadata for a single model (`GET /models/{id}`).
pub async fn Client::model(self : Client, id : String) -> Model raise LLMError {
  let json = self.get_json("/models/" + id)
  @json.from_json(json) catch {
    err => raise Decode(err.to_string())
  }
}