#' Fetch Banco de España (BdE) data
#'
#' Retrieve time series data from the BdE statistics API.
#'
#' @details
#' You can search for the series codes in the
#' [BIEST](https://app.bde.es/bie_www/bie_wwwias/xml/Arranque.html) application or in the tables
#' published by the Banco de España.
#'
#' @param key (`character()`)\cr
#'   The series keys to query.
#' @param time_range (`NULL` | `character(1)` | `integer(1)`)\cr
#'   The time range for the data. Can be an annual range (e.g., `2024`) or a frequency-based code:
#'   * Daily frequency (D): `"3M"` (last 3 months), `"12M"`, `"36M"`
#'   * Monthly frequency (M): `"30M"`, `"60M"`, `"MAX"` (entire series)
#'   * Quarterly frequency (Q): `"30M"`, `"60M"`, `"MAX"`
#'   * Annual frequency (A): `"60M"`, `"MAX"`
#'
#'   If `NULL` (default), returns the smallest range for the series frequency
#'   (e.g., `"30M"` for monthly series).
#' @param lang (`character(1)`)\cr
#'   Language to query, either `"en"` or `"es"`.
#' @returns A [data.table::data.table()] with the requested data.
#' @source <https://www.bde.es/webbe/en/estadisticas/recursos/api-estadisticas-bde.html>
#' @family data
#' @export
#' @examplesIf curl::has_internet()
#' \donttest{
#' bde_data("D_1NBAF472", time_range = "30M")
#' bde_data(c("DTNPDE2010_P0000P_PS_APU", "DTNSEC2010_S0000P_APU_SUMAMOVIL"), time_range = "MAX")
#' bde_data("DEEQ.N.ES.W1.S1.S1.T.B.G._Z._Z._Z.EUR._T._X.N.ALL", time_range = 2024)
#' }
bde_data <- function(key, time_range = NULL, lang = "en") {
  assert_character(key, min.chars = 1L)
  assert_period(time_range)
  assert_choice(lang, c("en", "es"))

  json <- bde(key, lang = lang, rango = time_range)
  parse_bde_data(json)
}

parse_bde_data <- function(json) {
  old_cols <- c(
    "serie",
    "descripcion",
    "descripcionCorta",
    "codFrecuencia",
    "decimales",
    "simbolo",
    "fechaInicio",
    "fechaFin",
    "fechas",
    "valores"
  )
  new_cols <- c(
    "key",
    "description",
    "title",
    "freq",
    "decimals",
    "symbol",
    "start_date",
    "end_date",
    "date",
    "value"
  )
  dt <- json |>
    map(function(x) {
      dt <- as.data.table(x[names(x) != "informacion"])
      meta <- x$informacion |>
        map(setDT) |>
        rbindlist() |>
        setnames(c("name", "value"))
      name <- NULL
      meta[, name := tolower(name)]
      meta[, name := chartr(" ", "_", tolower(name))]
      meta[, name := gsub("[()]", "", name)]
      exclude <- c(
        "name",
        "decimals",
        "first_value",
        "last_value",
        "number_of_observations",
        "min_value",
        "max_value"
      )
      meta <- meta[!name %in% exclude]
      meta <- transpose(meta, make.names = "name")
      setnames(meta, c("units", "description"), c("unit", "long_description"))
      dt[, names(meta) := meta]
    }) |>
    rbindlist(fill = TRUE) |>
    setnames(old_cols, new_cols)

  value <- NULL
  dt[, let(date = unlist(date, use.names = FALSE), value = unlist(value, use.names = FALSE))]
  dt[,
    names(.SD) := map(.SD, \(x) as.POSIXct(x, format = "%Y-%m-%dT%H:%M:%SZ", tz = "UTC")),
    .SDcols = patterns("date")
  ]
  setcolorder(dt, col_order, skip_absent = TRUE)
  dt[]
}

#' Fetch latest Banco de España (BdE) data
#'
#' Retrieve the most recently published value for one or more series from the BdE statistics API.
#'
#' @inheritParams bde_data
#' @returns A [data.table::data.table()] with the latest observation per series.
#' @source <https://www.bde.es/webbe/en/estadisticas/recursos/api-estadisticas-bde.html>
#' @family data
#' @export
#' @examplesIf curl::has_internet()
#' \donttest{
#' bde_latest("D_1NBAF472")
#' bde_latest(c("D_1NBAF472", "DTNPDE2010_P0000P_PS_APU"))
#' }
bde_latest <- function(key, lang = "en") {
  assert_character(key, min.chars = 1L)
  assert_choice(lang, c("en", "es"))

  json <- bde(key, lang = lang, resource = "favoritas")

  old_cols <- c(
    "serie",
    "descripcionCorta",
    "codFrecuencia",
    "decimales",
    "simbolo",
    "tendencia",
    "fechaValor",
    "valor"
  )
  new_cols <- c("key", "title", "freq", "decimals", "symbol", "trend", "date", "value")
  dt <- json |>
    map(setDT) |>
    rbindlist() |>
    setnames(old_cols, new_cols)
  dt[, date := as.POSIXct(date, format = "%Y-%m-%dT%H:%M:%SZ", tz = "UTC")]
  setcolorder(dt, col_order, skip_absent = TRUE)
  dt[]
}

bde <- function(key, ..., lang, resource = "listaSeries") {
  url <- sprintf("https://app.bde.es/bierest/resources/srdatosapp/%s", resource)
  request(url) |>
    req_user_agent(bbk_user_agent()) |>
    req_url_query(idioma = lang, series = key, ..., .multi = "comma") |>
    req_error(body = bde_error_body) |>
    req_bbk_retry() |>
    req_bbk_cache() |>
    req_perform() |>
    resp_body_json()
}

bde_error_body <- function(resp) {
  content_type <- resp_content_type(resp)
  if (identical(content_type, "application/json")) {
    json <- resp_body_json(resp)
    msg <- c(json$errMsgUsr, json$errMsgDebug)
    docs <- "See docs at <https://www.bde.es/webbe/en/estadisticas/recursos/api-estadisticas-bde.html>" # nolint
    c(msg, docs)
  }
}
