#' Computes error measures for estimated marginal likelihood.
#' @export
#' @title Error Measures for Estimated Marginal Likelihood
#' @param bridge_object an object of class \code{"bridge"} or \code{"bridge_list"} as returned from \code{\link{bridge_sampler}}.
#' @param na.rm a logical indicating whether missing values in logml estimates should be removed.  Ignored for the \code{bridge} method.
#' @param ... additional arguments (currently ignored).
#' @details Computes error measures for marginal likelihood bridge sampling estimates. The approximate errors for a \code{bridge_object} of class \code{"bridge"} that has been obtained with \code{method = "normal"} and \code{repetitions = 1} are based on Fruehwirth-Schnatter (2004).
#' Not applicable in case the object of class \code{"bridge"} has been obtained with \code{method = "warp3"} and \code{repetitions = 1}.
#' To assess the uncertainty of the estimate in this case, it is recommended to run the \code{"warp3"} procedure multiple times.
#' @return If \code{bridge_object} is of class \code{"bridge"} and has been obtained with \code{method = "normal"} and \code{repetitions = 1}, returns a list with components:
#' \itemize{
#'  \item \code{re2}: approximate relative mean-squared error for marginal likelihood estimate.
#'  \item \code{cv}: approximate coefficient of variation for marginal likelihood estimate (assumes that bridge estimate is unbiased).
#'  \item \code{percentage}: approximate percentage error of marginal likelihood estimate.
#' }
#' If \code{bridge_object} is of class \code{"bridge_list"}, returns a list with components:
  #' \itemize{
  #'  \item \code{min}: minimum of the log marginal likelihood estimates.
  #'  \item \code{max}: maximum of the log marginal likelihood estimates.
  #'  \item \code{IQR}: interquartile range of the log marginal likelihood estimates.
  #' }
#' @author Quentin F. Gronau
#' @note For examples, see \code{\link{bridge_sampler}} and the accompanying vignettes: \cr \code{vignette("bridgesampling_example_jags")} \cr \code{vignette("bridgesampling_example_stan")}
#'
#' @seealso The \code{summary} methods for \code{bridge} and \code{bridge_list} objects automatically invoke this function, see \code{\link{bridge-methods}}.
#'
#' @references
#' Fruehwirth-Schnatter, S. (2004). Estimating marginal likelihoods for mixture and Markov switching models using bridge sampling techniques. \emph{The Econometrics Journal, 7}, 143-167. \doi{10.1111/j.1368-423X.2004.00125.x}
#' @import Brobdingnag
#' @importFrom coda spectrum0.ar
#' @export
error_measures <- function (bridge_object, ...) {
  UseMethod("error_measures", bridge_object)
}

#' @rdname error_measures
#' @export
error_measures.bridge <- function(bridge_object,...) {

  if (bridge_object$method == "warp3") {
    stop(paste0("error_measures not implemented for warp3 method with",
                "\n  repetitions = 1.",
                "\n  We recommend to run the warp3 procedure multiple times",
                "\n  to assess the uncertainty of the estimate."))
  }

  e <- as.brob( exp(1) )

  ml <- e^(bridge_object$logml)
  g_p <- e^(bridge_object$q12)
  g_g <- e^(bridge_object$q22)
  priorTimesLik_p <- e^(bridge_object$q11)
  priorTimesLik_g <- e^(bridge_object$q21)
  p_p <- priorTimesLik_p/ml
  p_g <- priorTimesLik_g/ml

  N1 <- length(p_p)
  N2 <- length(g_g)
  s1 <- N1/(N1 + N2)
  s2 <- N2/(N1 + N2)

  f1 <- as.numeric( p_g/(s1*p_g + s2*g_g) )
  f2 <- as.numeric( g_p/(s1*p_p + s2*g_p) )
  rho_f2 <- spectrum0.ar( f2 )$spec

  term1 <- 1/N2 * var( f1 ) / mean( f1 )^2
  term2 <- rho_f2/N1 * var( f2 ) / mean( f2 )^2

  re2 <- term1 + term2

  # convert to coefficient of variation (assumes that bridge estimate is unbiased)
  cv <- sqrt(re2)

  # convert to percentage error
  percentage <- scales::percent(cv)
  return(list(re2 = re2, cv = cv, percentage = percentage))

}

#' @rdname error_measures
#' @export
error_measures.bridge_list <- function(bridge_object, na.rm = TRUE, ...) {

  return(list(min = min(bridge_object$logml, na.rm = na.rm),
              max = max(bridge_object$logml, na.rm = na.rm),
              IQR = stats::IQR(bridge_object$logml, na.rm = na.rm)))

}
