#' Return Finances One API data
#'
#' @param dataset_id (`character(1)`)\cr
#'   The ID of the associated dataset.
#' @param resource_id (`character(1)`)\cr
#'   The ID of the associated resource.
#' @param view_id (`character(1)`)\cr
#'   The ID of the view.
#' @param ... (`any`)\cr
#'   Additional arguments passed to the request.
#' @param limit (`NULL` | `integer(1)`)\cr
#'   The maximum number of rows to return. Default `NULL`.
#'   If `NULL`, all rows are returned.
#' @returns A `data.frame()` with the requested dataset.
#' @source <https://financesone.worldbank.org/data>
#' @export
#' @rdname fone
#' @examples
#' \dontrun{
#' # get dataset data
#' dataset <- fone_dataset(dataset_id = "DS00047", resource_id = "RS00005")
#' head(dataset)
#'
#' # get view data
#' view <- fone_view(view_id = "DS01538")
#' head(view)
#' }
fone_dataset <- function(dataset_id, resource_id, ..., limit = NULL) {
  stopifnot(
    is_string(dataset_id),
    is_string(resource_id),
    is_count(limit, null_ok = TRUE)
  )
  fone(
    resource = "apiservice",
    datasetId = dataset_id,
    resourceId = resource_id,
    ...,
    limit = limit
  )
}

#' @rdname fone
#' @export
fone_view <- function(view_id, ..., limit = NULL) {
  stopifnot(is_string(view_id), is_count(limit, null_ok = TRUE))
  fone(resource = "view", viewId = view_id, ..., limit = limit)
}

fone <- function(resource, ..., limit = NULL) {
  page_size <- min(limit %||% 1000L, 1000L)
  max_reqs <- if (!is.null(limit)) ceiling(limit / page_size) else Inf

  req <- wb_request("https://datacatalogapi.worldbank.org/dexapps/fone/api") |>
    req_error(body = \(resp) resp_body_string(resp, "UTF-8")) |>
    req_url_path_append(resource) |>
    req_url_query(top = page_size, type = "csv", ...)

  resps <- req_perform_iterative(
    req,
    next_req = iterate_with_offset(
      "skip",
      start = 0L,
      offset = page_size,
      resp_complete = \(resp) !resp_has_body(resp)
    ),
    max_reqs = max_reqs
  )

  data <- resps_data(resps, function(resp) {
    if (resp_has_body(resp)) {
      resp_body_csv(resp)
    }
  })
  if (!is.null(limit)) {
    data <- utils::head(data, limit)
  }
  clean_strings(data)
}
