#' Compute Model Error for Kernel Ridge Regression Models
#'
#' @description
#' Computes the model error for kernel ridge regression (\code{"krr"} object).
#' Returns the mean squared error (MSE) between the observed responses
#' and the fitted values stored in the object.
#'
#' @param x An object of class \code{"krr"}, typically returned by
#'   \code{\link{fastkrr}}.
#' @param data_new An optional data frame containing new predictor variables
#'   and the observed response variable. The response column must have the
#'   same name as the response variable used to fit the model. If
#'   \code{NULL}, the training MSE is computed. Otherwise, the prediction MSE (PMSE)
#'   is computed using predictions for \code{data_new}.
#' @param ... Additional arguments (ignored).
#'
#' @return A numeric value giving the mean squared error (MSE). If \code{data_new = NULL},
#'   this returns the training MSE based on the fitted values. If \code{data_new} is provided,
#'   it returns the prediction mean squared error (PMSE) evaluated on the new dataset.
#'
#' @details
#' This method computes the mean squared error defined as:
#' \deqn{\text{MSE} = \frac{1}{n} \sum_{i = 1} (y_i - \hat{y}_i)^2}
#' Depending on the presence of \code{data_new}, the components are defined as follows:
#' \itemize{
#'   \item If \code{data_new = NULL}, \eqn{y} is the observed response vector and
#'     \eqn{\hat{y}} is the fitted values vector, both stored within the \code{"krr"} object.
#'   \item If \code{data_new} is provided, \eqn{y} is the observed response extracted from
#'     \code{data_new} and \eqn{\hat{y}} is the predicted values vector generated by
#'     applying \code{\link{predict.krr}} to the new predictor variables.
#' }
#'
#' @seealso \code{\link{summary.krr}}, \code{\link{plot.krr}}, \code{\link{predict.krr}}
#'
#'
#' @examples
#' # Data setting
#' set.seed(1)
#' lambda = 1e-4
#' d = 1
#' n = 50
#' rho = 1
#' X = matrix(runif(n*d, 0, 1), nrow = n, ncol = d)
#' y = sin(2 * pi * rowMeans(X)^3) + rnorm(n, mean = 0, sd = 0.1)
#'
#' data = data.frame(X, y = y)
#'
#' model = fastkrr(data = data, response = "y", kernel = "gaussian",
#'                  opt = "exact", lambda = lambda)
#'
#' # MSE
#' error(model)
#'
#' new_n = 50
#' new_x = matrix(runif(new_n*d, 0, 1), nrow = new_n, ncol = d)
#' new_y = as.vector(sin(2*pi*rowMeans(new_x)^3) + rnorm(new_n, 0, 0.1))
#' new_data = data.frame(new_x, y = new_y)
#'
#' # PMSE
#' error(model, data_new = new_data)
#'
#' @name error.krr
NULL


#' @rdname error.krr
#' @export
error = function(x, ...) {
  UseMethod("error")
}

#' @rdname error.krr
#' @export
error.krr = function(x, data_new = NULL, ...) {
  model = x

  if (is.null(data_new)){ # Training MSE
    return(as.numeric(
      crossprod(model$y - model$fitted.values) / length(model$y)
    ))
  }else{ # Prediction MSE
    if (!is.data.frame(data_new)) stop("data_new must be a data.frame")
    if (anyNA(data_new)) stop("data_new contains missing values (NA).")
    if (!model$call$response %in% names(data_new)) stop("Response variable not found in data_new.")

    y_new = data_new[[model$call$response]]
    x_new = as.matrix(
      data_new[, setdiff(names(data_new), model$call$response), drop = FALSE]
    )

    pred = predict(model, newdata = x_new)

    as.numeric(
      crossprod(y_new - pred) / length(y_new)
    )
  }
}
