#' @importFrom rlang .data
#' @importFrom stats predict
evaluate_onam_single <- function(model,
                                 data,
                                 model_info,
                                 categorical_features) {
  data_fit <- prepare_data(data, model_info,
                           categorical_features)
  model_idx_list <- get_model_idx_list(model_info)
  u_object <-
    get_u(model$model_list, model_idx_list, model_info, data_fit)
  predictions_submodel <-
    lapply(model$w_list,
           function(w)
             u_object$u %*% w)
  predictions_submodel_old <-
    lapply(model$w_list_old,
           function(w)
             u_object$u %*% w)
  model_names <- get_all_effect_names(model_info)
  names(predictions_submodel) <- model_names
  names(predictions_submodel_old) <- model_names
  list(predictions_submodel = predictions_submodel,
       predictions_submodel_old = predictions_submodel_old)
}
#' Evaluate orthogonal neural additive model
#' @docType methods
#' @param object model of class `onam` as returned from [onam] to be
#' evaluated
#' @param newdata Data for which the model is to be evaluated. If NULL (default),
#' data with which \code{model} was fitted is used.
#' @returns Returns a list containing data, model output for each observation in
#' `newdata` and main and interaction effects obtained by the model
#' @param ... some methods for this generic require additional arguments. None
#' are used in this method.
#' @aliases predict
#' @method predict onam
#' @export
predict.onam <- function(object, newdata = NULL, ...) {
  if (!require_keras()) {
    invisible(return(NULL))
  }
  if (is.null(newdata)) {
    newdata <- object$data
  }
  model_info <- object$model_info
  n <- nrow(newdata)
  n_ensemble <- length(object$ensemble)
  categorical_features <- object$categorical_features
  predictions_separate <-
    lapply(
      object$ensemble,
      evaluate_onam_single,
      data = newdata,
      model_info = model_info,
      categorical_features = categorical_features
    )
  effect_names <- names(predictions_separate[[1]][[1]])
  n_effects <- length(effect_names)
  data_predictions <-
    data.frame(
      y = unlist(predictions_separate),
      effect =
        rep(rep(effect_names,
                each = n),
            2 * n_ensemble),
      onam = rep(rep(c("after", "before"),
                     each = n * n_effects),
                 n_ensemble),
      observation = rep(1:n, n_effects * 2 * n_ensemble),
      model = rep(1:n_ensemble, each = n * 2 * n_effects)
    )
  predictions_features_ensemble <-
    lapply(effect_names,
           function(effect_name) {
             data_predictions %>%
               dplyr::filter(.data$onam == "after",
                             .data$effect == effect_name) %>%
               dplyr::group_by(.data$observation) %>%
               dplyr::summarise(totaleffect = mean(.data$y)) %>%
               dplyr::select(.data$totaleffect) %>% unlist()
           })
  names(predictions_features_ensemble) <-
    effect_names
  predictions_features <-
    unlist(predictions_features_ensemble) %>%
    matrix(nrow = n) %*%
    object$w_post_ensemble
  colnames(predictions_features) <-
    effect_names
  predictions_total <-
    data_predictions %>%
    dplyr::filter(.data$onam == "after") %>%
    dplyr::group_by(.data$observation) %>%
    dplyr::summarise(prediction = sum(.data$y) / n_ensemble) %>%
    dplyr::select(.data$prediction) %>% unlist()
  out <- list(
    data = newdata,
    predictions = predictions_total,
    feature_effects = predictions_features,
    model_info = model_info
  )
  class(out) <- "onam_prediction"
  out
}
evaluate_onam_pre <- function(model_list) {
  data <- model_list$data
  model_info <- model_list$model_info
  categorical_features <- model_list$categorical_features
  n <- nrow(data)
  n_ensemble <- length(model_list$ensemble)
  predictions_separate <-
    lapply(
      model_list$ensemble,
      evaluate_onam_single,
      data = data,
      model_info = model_info,
      categorical_features = categorical_features
    )
  effect_names <- names(predictions_separate[[1]][[1]])
  n_effects <- length(effect_names)
  data_predictions <-
    data.frame(
      y = unlist(predictions_separate),
      effect =
        rep(rep(effect_names,
                each = n),
            2 * n_ensemble),
      onam = rep(rep(c("after", "before"),
                     each = n * n_effects),
                 n_ensemble),
      observation = rep(1:n, n_effects * 2 * n_ensemble),
      model = rep(1:n_ensemble, each = n * 2 * n_effects)
    )
  predictions_features_ensemble <-
    lapply(effect_names,
           function(effect_name) {
             data_predictions %>%
               dplyr::filter(.data$onam == "after",
                             .data$effect == effect_name) %>%
               dplyr::group_by(.data$observation) %>%
               dplyr::summarise(totaleffect = mean(.data$y)) %>%
               dplyr::select(.data$totaleffect) %>% unlist()
           })
  names(predictions_features_ensemble) <-
    effect_names
  predictions_total <-
    data_predictions %>%
    dplyr::filter(.data$onam == "after") %>%
    dplyr::group_by(.data$observation) %>%
    dplyr::summarise(prediction = sum(.data$y) / n_ensemble) %>%
    dplyr::select(.data$prediction) %>% unlist()
  list(
    data = data,
    predictions_total = predictions_total,
    data_predictions = data_predictions,
    predictions_features_ensemble = predictions_features_ensemble
  )
}
