# WARNING - Generated by {fusen} from dev/flat_kwb_simulate_inflow.Rmd: do not edit by hand # nolint: line_length_linter.

#' Create random distribution
#' 
#' This function does the same thing as kwb.utils::create_random_distribution(),
#' but it is bundled with *ambre* to avoid a hard dependency on the
#' unmaintained package.
#' 
#' @param type "uniform" calls runif(), "log10_uniform" calls 
#' 10^runif(number_of_events, log10_min, log10_max), "triangle" calls 
#' EnvStats::rtri(), "lognorm" calls rlnorm(), "norm" calls rnorm() and 
#' "log10_norm" calls 10^rnorm(number_of_events, mean = log10_mean, 
#' sdev = log10_sdev), (default: "uniform") 
#' @param number_of_repeatings how often should the random distribution with the
#' same parameters be generated (default: 1)
#' @param  number_of_events number of events
#' @param value constant value (no random number), gets repeated number_of_events
#' times (if 'type' = 'value')
#' @param min minimum value (default: 10), only used if 'type' is "runif" or
#' "triangle"
#' @param max maximum value (default: 1000), only used if 'type' is "runif" or
#' "triangle"
#' @param percent_within_minmax percent of data point within min/max (default: 
#' 0.9 i.e. 90 percent
#' @param min_zero  only used if 'type' is "log10_uniform" or 
#' "log10_norm", "norm" or "lognorm" and "min" value equal zero. 
#' In this case the zero is replaced by this value (default: 0.01), see also
#' \code{default_min()}
#' @param log10_min minimum value (default: default_min(min, max, 
#' min_zero, f = log10)), only used if 'type' is "log10_uniform" or "log10_norm"
#' @param log10_max maximum value (default: ifelse(max > 0, log10(max), 
#' log10_zero_threshold), only used if 'type' is "log10_uniform" or "log10_norm"
#' @param log10_mean mean value (default: (log10_min + log10_max)/2), only used 
#' if 'type' is "log10_norm"
#' @param log10_sdev standard deviation (default: abs((log10_max- log10_mean) / 
#' get_percentile(0.95)), only used if 'type' is "log10_norm"
#' @param mean mean value (default: (default_min(min, max, min_zero) / 
#' default_max(max, 10*min_zero)) / 2), only used if 'type' is "norm"
#' @param sdev standard deviation (default: abs((default_max(max, 10*min_zero) - 
#' mean) / get_percentile(0.95))), only used if 'type' is "norm"
#' @param meanlog log mean value (default: mean(log((min + max) / 2))), only
#' used if 'type' is "lognorm"
#' @param sdlog standard deviation (default: abs(sd(c(default_min(min, max, 
#' min_zero, f = log)))) ), only used if 'type' is "lognorm"
#' @param mode (default: default_min(min, max, min_zero) + 
#' default_max(max, 10 * min_zero) / 2), only used if 'type' is "triangle"
#' @param debug print debug information (default: TRUE)
#' @return list with parameters of user defined random distribution and
#' corresponding values
#' @references
#'   Sonnenberg H (2024). kwb.utils: General Utility Functions Developed at KWB. R package version 0.15.0
#'   URL: \url{https://github.com/kwb-r/kwb.utils}
#'   (MIT Licence)
#' @export
#' @importFrom stats sd qnorm runif rnorm rlnorm
#' @importFrom dplyr mutate
#' @importFrom rlang .data
#' @importFrom EnvStats rtri
#' 
#' @examples
#'
#' # Example usage of create_random_distribution
#' # Uniform distribution
#' uniform_dist <- create_random_distribution(
#'   type = "uniform",
#'   number_of_repeatings = 2,
#'   number_of_events = 10,
#'   min = 0,
#'   max = 100
#' )
#'
#' # Log10 uniform distribution
#' log10_uniform_dist <- create_random_distribution(
#'   type = "log10_uniform",
#'   number_of_events = 10,
#'   min = 1,
#'   max = 1000
#' )
#'
#' # Triangle distribution
#' triangle_dist <- create_random_distribution(
#'   type = "triangle",
#'   number_of_events = 10,
#'   min = 0,
#'   max = 100,
#'   mode = 50
#' )
#'
#' # Normal distribution
#' norm_dist <- create_random_distribution(
#'   type = "norm",
#'   number_of_events = 10,
#'   mean = 50,
#'   sdev = 10
#' )
#'
#' # Log10 normal distribution
#' log10_norm_dist <- create_random_distribution(
#'   type = "log10_norm",
#'   number_of_events = 10,
#'   log10_mean = 2,
#'   log10_sdev = 0.5
#' )
#'
#' # Lognormal distribution
#' lognorm_dist <- create_random_distribution(
#'   type = "lognorm",
#'   number_of_events = 10,
#'   meanlog = 2,
#'   sdlog = 0.5
#' )
#'
#' # Constant value
#' value_dist <- create_random_distribution(
#'   type = "value",
#'   number_of_events = 10,
#'   value = 42
#' )
create_random_distribution <- function(
  type = "uniform",
  number_of_repeatings = 1,
  number_of_events = 365,
  value = 10,
  min = 10,
  max = 1000,
  percent_within_minmax = 0.9,
  min_zero = 0.01,
  log10_min = default_min(min, max, min_zero, f = log10), 
  log10_max = default_max(max, min_zero * 10, f = log10),
  log10_mean = (log10_min + log10_max) / 2,
  log10_sdev = abs((log10_max - log10_mean) / get_percentile(percent_within_minmax)),
  mean = (default_min(min, max, min_zero) + default_max(max, 10*min_zero)) / 2,
  sdev = abs((default_max(max, 10*min_zero) - mean) / get_percentile(percent_within_minmax)),
  meanlog = mean(log(default_min(min, max, min_zero) + default_max(max, 10 * min_zero)) / 2),
  sdlog = abs(sd(c(default_min(min, max, min_zero, f = log), 
                   default_max(max, 10 * min_zero, f = log)))),
  mode = (default_min(min, max, min_zero) + default_max(max, 10 * min_zero)) / 2,
  debug = TRUE
)
{
  # Inline helper functions 
  
  # Print a message if debug is TRUE
  debug_formatted <- function(fmt, ...) if (debug) cat(sprintf(fmt, ...))

  # Consistent message text
  distribution_text <- function(type_text, ...) paste0(
    "Create ", number_of_repeatings, " random distribution(s): ",
    type_text, " (n: ", number_of_events, ..., ")\n"
  )

  # Creation of paramter data frame
  paras_data_frame <- function(...) data.frame(
    type = type, 
    repeatings = number_of_repeatings,
    events = number_of_events,
    ...
  )
  
  # Creation of event data frame
  event_data_frame <- function(...) distribution_repeater(
    number_of_repeatings = number_of_repeatings,
    number_of_events = number_of_events,
    ...
  )
  
  # Product of numbers, to be reused
  number_product <- number_of_events * number_of_repeatings
  
  if (type == "value") {
    
    debug_formatted(
      "Replicate %d times constant value %f\n", number_product, value
    )

    events <- data.frame(
      repeatID = unlist(lapply(
        seq_len(number_of_repeatings), rep, number_of_events
      )),
      eventID = rep(seq_len(number_of_events), number_of_repeatings),
      values = rep(value, number_product)
    )
    
    paras <- paras_data_frame(value = value)
    
  } else if (type == "uniform") {
    
    debug_formatted(
      distribution_text("uniform", ", min: %f, max: %f"), 
      min, max
    )
    
    events <- event_data_frame(func = runif, min = min, max = max)
    paras <- paras_data_frame(min = min, max = max)
    
  } else if (type == "log10_uniform") {
    
    debug_formatted(
      distribution_text("10^runif", ", min: %f, max: %f"), 
      log10_min, log10_max
    )

    events <- event_data_frame(
      func = runif, min = log10_min, max = log10_max
    ) |> 
      dplyr::mutate(values = 10^.data$values)
    
    paras <- paras_data_frame(min = log10_min, max = log10_max)
    
  } else if (type == "norm") {
    
    debug_formatted(
      distribution_text("norm", ", mean: %f, sd: %f"), mean, sdev
    )
    
    events <- event_data_frame(func = rnorm, mean = mean, sd = sdev)
    paras <- paras_data_frame(mean = mean, sd = sdev)
    
  } else if (type == "log10_norm") {
    
    debug_formatted(
      distribution_text("10^rnorm ", ", mean: %f, sd: %f"),
      log10_mean, log10_sdev
    )
    
    events <- event_data_frame(
      func = rnorm, mean = log10_mean, sd = log10_sdev
    ) |> 
      dplyr::mutate(values = 10^.data$values)
    
    paras <- paras_data_frame(mean = log10_mean, sd = log10_sdev)
    
  } else if (type == "lognorm") {
    
    debug_formatted(
      distribution_text("lognorm", ", meanlog: %f, sdlog: %f"), 
      meanlog, sdlog
    )
    
    events <- event_data_frame(func = rlnorm, meanlog = meanlog, sdlog = sdlog)
    paras <- paras_data_frame(meanlog = meanlog, sdlog = sdlog)
    
  } else if (type == "triangle") {
    
    debug_formatted(
      distribution_text("triangle", ", min: %f, max: %f, mode = %f"),
      min, max, mode
    )
    
    events <- event_data_frame(
      func = EnvStats::rtri, min = min, max = max, mode = mode
    )
    paras <- paras_data_frame(min = min, max = max, mode = mode)
    
  } else {
    
    stop(sprintf(get_stop_text("no_such_distribution"), type), call. = FALSE)
  }

  list(events = events, paras = paras)
}
