#' Transform quantile model output into a forecast object
#'
#' @param model_out_tbl Model output tibble with predictions
#' @param oracle_output Predictions that would have been generated by an oracle
#' model that knew the observed target data values in advance
#'
#' @return forecast_quantile
#'
#' @examplesIf requireNamespace("hubExamples", quietly = TRUE)
#' quantile_forecast <- hubExamples::forecast_outputs |>
#'   dplyr::filter(.data[["output_type"]] == "quantile") |>
#'   transform_quantile_model_out(
#'     oracle_output = hubExamples::forecast_oracle_output
#'   )
#' quantile_forecast
#'
#' @importFrom rlang .data
#' @export
transform_quantile_model_out <- function(model_out_tbl, oracle_output) {
  model_out_tbl <- validate_model_oracle_out(model_out_tbl, oracle_output)

  task_id_cols <- get_task_id_cols(model_out_tbl)

  model_out_tbl <- model_out_tbl |>
    dplyr::filter(.data[["output_type"]] == "quantile") |>
    dplyr::mutate(output_type_id = as.numeric(.data[["output_type_id"]])) |>
    dplyr::rename(model = "model_id")

  # Filter oracle_output to quantile rows only when it still carries the
  # `output_type` column (i.e. mixed output types).
  if ("output_type" %in% colnames(oracle_output)) {
    oracle_output <- dplyr::filter(
      oracle_output,
      .data[["output_type"]] == "quantile"
    )
  }
  # Always drop output_type/output_type_id if present: output_type_id can
  # remain after a user-side filter that removed output_type, and a stray
  # output_type_id breaks `as_forecast_quantile`.
  oracle_output <- dplyr::select(
    oracle_output,
    -dplyr::any_of(c("output_type", "output_type_id"))
  )

  data <- dplyr::left_join(
    model_out_tbl,
    oracle_output,
    by = task_id_cols[task_id_cols %in% colnames(oracle_output)],
    relationship = "many-to-one"
  )

  forecast_quantile <- scoringutils::as_forecast_quantile(
    data,
    forecast_unit = c("model", task_id_cols),
    observed = "oracle_value",
    predicted = "value",
    quantile_level = "output_type_id"
  )

  forecast_quantile
}
