///|
/// Metadata for a file stored at the endpoint (`/files`).
pub(all) struct FileObject {
  id : String
  bytes : Int64
  created_at : Int64
  filename : String
  purpose : String
} derive(Debug)

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

///|
/// The response from `GET /files`.
pub(all) struct FileList {
  data : Array[FileObject]
} derive(Debug)

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

///|
/// The result of deleting a file.
pub(all) struct DeletionResult {
  id : String
  deleted : Bool
} derive(Debug)

///|
pub impl @json.FromJson for DeletionResult with fn from_json(
  json : Json,
  path : @json.JsonPath,
) -> DeletionResult {
  guard json is Object(obj) else {
    raise @json.JsonDecodeError((path, "DeletionResult: expected object"))
  }
  let id = match obj.get("id") {
    Some(String(s)) => s
    _ => ""
  }
  let deleted = match obj.get("deleted") {
    Some(True) => true
    _ => false
  }
  { id, deleted }
}

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

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

///|
/// Delete a file (`DELETE /files/{id}`).
pub async fn Client::delete_file(
  self : Client,
  id : String,
) -> DeletionResult raise LLMError {
  let json = self.delete_json("/files/" + id)
  @json.from_json(json) catch {
    err => raise Decode(err.to_string())
  }
}