#' @title Plot Posterior OSL-Age Summary
#'
#' @description
#' The function produces a graphical summary of the statistical inference of
#' an OSL age.
#'
#' @details The function is called automatically by [Luminescence::combine_De_Dr].
#'
#' @param object [Luminescence::RLum.Results-class], [numeric] (**required**):
#' an object produced by [Luminescence::combine_De_Dr]. Alternatively, a [numeric] vector of
#' a parameter from an MCMC process.
#'
#' @param level [numeric] (*with default*):
#' probability of shown credible interval.
#'
#' @param digits [integer] (*with default*):
#' number of digits considered for the calculation.
#'
#' @param verbose [logical] (*with default*): enable/disable output to the
#' terminal.
#'
#' @param ... further arguments to modify the plot, supported: `xlim`, `ylim`,
#' `xlab`, `ylab`, `main`, `lwd`, `lty`, `col`, `rug`, `polygon_col`,
#' `polygon_density`.
#'
#'@return A posterior distribution plot and an [Luminescence::RLum.Results-class]
#' object with the credible interval.
#'
#' @author
#' Anne Philippe, Université de Nantes (France)\cr
#' Jean-Michel Galharret, Université de Nantes (France)\cr
#' Norbert Mercier, IRAMAT-CRP2A, Université Bordeaux Montaigne (France)\cr
#' Sebastian Kreutzer, F2.1 Geophysical Parametrisation/Regionalisation, LIAG - Institute for Applied Geophysics (Germany)\cr
#'
#'@section Function version: 0.1.0
#'
#'@seealso [Luminescence::combine_De_Dr], [plot.default], [rjags::rjags]
#'
#'@keywords hplot dplot
#'
#'@examples
#'##generate random data
#'set.seed(1234)
#'object <- rnorm(1000, 100, 10)
#'plot_OSLAgeSummary(object)
#'
#'@export
plot_OSLAgeSummary <- function(
  object,
  level = 0.95,
  digits = 1L,
  verbose = TRUE,
  ...
) {
  .set_function_name("plot_OSLAgeSummary")
  on.exit(.unset_function_name(), add = TRUE)

  ## Integrity checks -------------------------------------------------------
  .validate_class(object, c("RLum.Results", "numeric"))
  .validate_positive_scalar(level)
  .validate_positive_scalar(digits, int = TRUE)

  if (inherits(object, "RLum.Results")) {
    if (.check_originator(object, c(".calc_BayesianCentralAgeModel",
                                    ".calc_IndividualAgeModel"))) {
      data.object <- "A"
    } else if (.check_originator(object, "combine_De_Dr")) {
      data.object <- "Ages"
    } else {
      .throw_error("'object' was created by an unsupported function ",
                   "(originator is '", object@originator, "')")
    }
    object <- get_RLum(object, data.object = data.object)
  }

  if (any(is.infinite(object))) {
    .throw_warning("Inf values found in 'object', removed")
    object <- object[!is.infinite(object)]
  }

  ## A should be a matrix
  A <- as.matrix(object, ncol = 1)

# Run calculations --------------------------------------------------------
  ## use our internal function instead of Archaeophase to avoid dependency hell
  CI <- tryCatch(round(.calc_HPDI(A, prob = level), digits),
                 error = function(e) {
                   .throw_error(gsub("'x'", "'object'", e$message))
                 })
  Bayes_est_mean <- round(mean(A), digits = digits)
  Bayes_est_sd <- round(sd(A), digits = digits)

# Terminal output ---------------------------------------------------------
  if(verbose){
    cat("\n[plot_OSLAgeSummary()]\n")
    cat(paste0(" Credible Interval (", level * 100 ),"%): ",paste(CI[1,], collapse = " : "), "\n")
    cat(paste0(" Bayes estimate (posterior mean \u00b1 sd): ", Bayes_est_mean[1], " \u00b1 ", Bayes_est_sd[1]),"\n")
  }

# Plot output -------------------------------------------------------------
  density_A <- density(A)

  plot_settings <- modifyList(x = list(
    xlim = range(A),
    ylim = range(density_A$y),
    main = "Posterior distr. of A",
    xlab = "Age [ka]",
    ylab = "Density",
    lwd = 1,
    lty = 1,
    col = "black",
    polygon_col = rgb(1,0,0,0.3),
    polygon_density = 20,
    rug = FALSE
  ), val = list(...))

  plot(
    x = density_A$x,
    y = density_A$y,
    xlim = plot_settings$xlim,
    ylim = plot_settings$ylim * 1.07,
    xlab = plot_settings$xlab,
    ylab = plot_settings$ylab,
    main = plot_settings$main,
    type = "l",
    lwd = plot_settings$lwd,
    lty = plot_settings$lty,
    col = plot_settings$col
  )

  ## add lines on the top for the CI
  lines(x = c(CI[1,]), y = rep(par()$usr[4] * 0.92, 2))
  lines(x = rep(CI[1,1], 2), y = c(par()$usr[4] * 0.91, par()$usr[4] * 0.92))
  lines(x = rep(CI[1,2], 2), y = c(par()$usr[4] * 0.91, par()$usr[4] * 0.92))

  ## add polygon fill
  polygon(
    x = c(density_A$x, rev(density_A$x)),
    y = c(density_A$y, rep(0, length(density_A$y))),
    col = plot_settings$polygon_col,
    lty = 0,
    density = NULL
  )

  ## add CI
  xy_id <- density_A$x >= CI[1,1] & density_A$x <= CI[1,2]
  polygon(
    x = c(density_A$x[xy_id], rev(density_A$x[xy_id])),
    y = c(density_A$y[xy_id], rep(0, length(density_A$y[xy_id]))),
    col = "black",
    lwd = 0.5,
    border = TRUE,
    density = plot_settings$polygon_density
  )

  ##add rug
  if (plot_settings$rug) graphics::rug(A)

  ## add text
  text(x = density_A$x[xy_id][1], y = density_A$y[xy_id][2], CI[1,1], pos = 2, cex = 0.6)
  text(x = max(density_A$x[xy_id]), y = rev(density_A$y[xy_id])[1], CI[1,2], pos = 4, cex = 0.6)
  text(
    x = median(density_A$x[xy_id]),
    y = par()$usr[4] * 0.91,
    labels = paste0("CI: ", level[1] * 100, "%"),
    pos = 3,
    cex = 0.6
  )

# Return ------------------------------------------------------------------
  set_RLum("RLum.Results",
    data = list(
      Estimate = Bayes_est_mean,
      Credible_Interval = CI,
      level = level),
    info = list(call = sys.call()))
}
