#' Download and Process Data from FRED
#'
#' Downloads a specified data series from the Federal Reserve Economic Data
#' (FRED) website, processes the data, and returns it as a tibble.
#'
#' @details
#' Constructs the URL based on the provided FRED series ID, performs an HTTP
#' GET request to download the data in CSV format, and processes it to a tidy
#' tibble format. The resulting tibble includes the date, value, and the series
#' ID.
#'
#' This approach is inspired by `quantmod::getSymbolsFRED()` which uses a
#' different wrapper around the same FRED download data site. If you want to
#' systematically download FRED data via API, please consider using the `fredr`
#' package.
#'
#' @param series A character vector specifying the FRED series ID(s) to
#'   download.
#' @param start_date Optional. A character string or Date object in
#'   "YYYY-MM-DD" format specifying the start date for the data. If not
#'   provided, the full dataset is returned.
#' @param end_date Optional. A character string or Date object in
#'   "YYYY-MM-DD" format specifying the end date for the data. If not
#'   provided, the full dataset is returned.
#'
#' @returns A tibble containing the processed data with three columns:
#' \describe{
#'   \item{date}{The date corresponding to the data point.}
#'   \item{value}{The value of the data series at that date.}
#'   \item{series}{The FRED series ID corresponding to the data.}
#' }
#'
#' @family download functions
#' @export
#'
#' @examples
#' \donttest{
#'   download_data_fred("CPIAUCNS")
#'   download_data_fred(c("GDP", "CPIAUCNS"), "2010-01-01", "2010-12-31")
#' }
#'
download_data_fred <- function(series, start_date = NULL, end_date = NULL) {
  dates <- validate_dates(start_date, end_date)
  start_date <- dates$start_date
  end_date <- dates$end_date

  fred_processed <- list()

  cli::cli_progress_bar(
    "Downloading series",
    total = length(series),
    clear = TRUE
  )
  for (j in seq_along(series)) {
    url <- paste0(
      "https://fred.stlouisfed.org/graph/fredgraph.csv?id=",
      series[j]
    )

    response <- handle_download_error(
      function() {
        httr2::request(url) |>
          httr2::req_error(is_error = \(resp) FALSE) |>
          httr2::req_perform()
      },
      fallback = NULL
    )

    if (!is.null(response)) {
      if (response$status_code == 200) {
        fred_raw <- suppressWarnings(httr2::resp_body_string(response)) |>
          textConnection() |>
          read.csv() |>
          as_tibble()

        fred_processed[[j]] <- fred_raw |>
          mutate(
            date = as.Date(.data$observation_date),
            value = as.numeric(.data[[series[j]]]),
            series = series[j],
            .keep = "none"
          )
      } else {
        cli::cli_warn(
          paste(
            "Failed to retrieve data for series {series[j]}",
            "with status code {response$status_code}."
          )
        )
        fred_processed[[j]] <- tibble(
          date = Date(),
          value = numeric(),
          series = character()
        )
      }
    } else {
      fred_processed[[j]] <- tibble(
        date = Date(),
        value = numeric(),
        series = character()
      )
    }

    cli::cli_progress_update()
  }

  fred_processed <- bind_rows(fred_processed)

  if (!is.null(start_date) && !is.null(end_date)) {
    fred_processed <- fred_processed |>
      filter(date >= start_date & date <= end_date)
  }

  fred_processed
}
