#' Compute Distribution-Free p-values for Simple Hypotheses
#'
#' Obtains p-values for EDF goodness-of-fit statistics via Monte Carlo simulation
#' from Uniform(0,1) order statistics.
#'
#' @param u_obs Observed order statistics u_1:n < ... < u_r:n.
#' @param n Total sample size.
#' @param r Number of observed failures.
#' @param censoring Type of censoring: \code{"right"} or \code{"left"}.
#' @param nsim Number of Monte Carlo simulation replicates (default 2000).
#' @param seed Optional random seed.
#'
#' @return Named numeric vector of empirical p-values for each statistic.
#' @export
pvalue_distribution_free <- function(u_obs,
                                     n,
                                     r,
                                     censoring = c("right", "left"),
                                     nsim = 2000,
                                     seed = NULL) {
  censoring <- match.arg(censoring)
  if (!is.null(seed)) {
    if (exists(".Random.seed", envir = .GlobalEnv)) {
      old_seed <- get(".Random.seed", envir = .GlobalEnv)
      on.exit(assign(".Random.seed", old_seed, envir = .GlobalEnv), add = TRUE)
    }
    set.seed(seed)
  }

  obs_edf <- stat_edf_censored(u_obs, n)
  obs_dir <- stat_direct_censored(u_obs, n)
  obs_all <- c(obs_edf, obs_dir)

  sim_stats <- matrix(NA_real_, nrow = nsim, ncol = length(obs_all))
  colnames(sim_stats) <- names(obs_all)

  for (b in 1:nsim) {
    unif_sample <- sort(stats::runif(n))
    if (censoring == "right") {
      u_sim <- unif_sample[1:r]
    } else {
      u_sim <- unif_sample[(n - r + 1):n]
      u_sim <- 1 - u_sim[r:1]
    }

    edf_b <- stat_edf_censored(u_sim, n)
    dir_b <- stat_direct_censored(u_sim, n)
    sim_stats[b, ] <- c(edf_b, dir_b)
  }

  p_vals <- numeric(length(obs_all))
  names(p_vals) <- names(obs_all)

  for (j in seq_along(obs_all)) {
    obs_val <- obs_all[j]
    if (is.na(obs_val)) {
      p_vals[j] <- NA_real_
    } else {
      p_vals[j] <- mean(sim_stats[, j] >= obs_val, na.rm = TRUE)
    }
  }

  p_vals
}

# Helper to sample from arbitrary CDF
q_generic <- function(p_vec, cdf, params) {
  check_zero <- tryCatch(eval_func(cdf, 0, params), error = function(e) NA_real_)
  is_nonneg <- !is.na(check_zero) && check_zero >= 0 && check_zero <= 0.05

  sapply(p_vec, function(u) {
    low <- if (is_nonneg) 0 else -10
    high <- 10
    step <- 10

    if (!is_nonneg) {
      count <- 0
      while (tryCatch(eval_func(cdf, low, params), error = function(e) 1) > u && count < 50) {
        low <- low - step
        step <- step * 2
        count <- count + 1
      }
    }

    step <- 10
    count <- 0
    while (tryCatch(eval_func(cdf, high, params), error = function(e) 0) < u && count < 50) {
      high <- high + step
      step <- step * 2
      count <- count + 1
    }

    res <- tryCatch(
      stats::uniroot(function(x) eval_func(cdf, x, params) - u, lower = low, upper = high)$root,
      error = function(e) NA_real_
    )
    res
  })
}

#' Compute Parametric Bootstrap p-values for Composite Hypotheses
#'
#' Obtains p-values for composite hypothesis tests where parameters are estimated from data.
#'
#' @param data Observed data vector of length r.
#' @param n Total sample size.
#' @param pdf Density function.
#' @param cdf Distribution function.
#' @param sf Survival function.
#' @param params_hat Estimated parameter list from observed data.
#' @param censoring Type of censoring.
#' @param transform Transformation method (\code{"ms"}, \code{"malmquist"}, or \code{"both"}).
#' @param nsim Number of bootstrap replicates (default 2000).
#' @param seed Optional random seed.
#' @param optim_control Optional control list passed to \code{optim}.
#'
#' @return A list containing empirical p-values and number of valid replicates.
#' @export
pvalue_parametric_bootstrap <- function(data,
                                        n,
                                        pdf,
                                        cdf,
                                        sf = NULL,
                                        params_hat,
                                        censoring = c("right", "left"),
                                        transform = c("both", "malmquist", "ms"),
                                        nsim = 2000,
                                        seed = NULL,
                                        optim_control = list()) {
  censoring <- match.arg(censoring)
  transform <- match.arg(transform)

  if (!is.null(seed)) {
    if (exists(".Random.seed", envir = .GlobalEnv)) {
      old_seed <- get(".Random.seed", envir = .GlobalEnv)
      on.exit(assign(".Random.seed", old_seed, envir = .GlobalEnv), add = TRUE)
    }
    set.seed(seed)
  }

  r <- length(data)

  # Compute observed composite statistics
  calc_comp <- function(trans_type) {
    stat_composite_mle(data = data, n = n, pdf = pdf, cdf = cdf, sf = sf,
                       params = params_hat, censoring = censoring,
                       transform = trans_type, optim_control = optim_control)
  }

  obs_ms <- if (transform %in% c("both", "ms")) calc_comp("ms") else NULL
  obs_mal <- if (transform %in% c("both", "malmquist")) calc_comp("malmquist") else NULL

  boot_ms_W2 <- numeric(nsim)
  boot_ms_A2 <- numeric(nsim)
  boot_mal_W2 <- numeric(nsim)
  boot_mal_A2 <- numeric(nsim)

  valid_count <- 0

  for (b in 1:nsim) {
    u_rand <- sort(stats::runif(n))
    x_sim <- q_generic(u_rand, cdf, params_hat)

    if (any(is.na(x_sim))) next

    if (censoring == "right") {
      data_b <- x_sim[1:r]
    } else {
      data_b <- x_sim[(n - r + 1):n]
    }

    # Re-estimate MLE on bootstrap sample
    fit_b <- tryCatch(
      fit_mle(data = data_b, n = n, pdf = pdf, cdf = cdf, sf = sf,
              params = params_hat, censoring = censoring, optim_control = optim_control),
      error = function(e) NULL
    )

    if (is.null(fit_b) || fit_b$convergence != 0) next

    # Compute bootstrap composite statistics
    comp_b_ms <- tryCatch(
      stat_composite_mle(data = data_b, n = n, pdf = pdf, cdf = cdf, sf = sf,
                         params = fit_b$par, censoring = censoring,
                         transform = "ms", optim_control = optim_control),
      error = function(e) NULL
    )

    comp_b_mal <- tryCatch(
      stat_composite_mle(data = data_b, n = n, pdf = pdf, cdf = cdf, sf = sf,
                         params = fit_b$par, censoring = censoring,
                         transform = "malmquist", optim_control = optim_control),
      error = function(e) NULL
    )

    if (transform %in% c("both", "ms") && is.null(comp_b_ms)) next
    if (transform %in% c("both", "malmquist") && is.null(comp_b_mal)) next

    valid_count <- valid_count + 1

    if (transform %in% c("both", "ms")) {
      boot_ms_W2[valid_count] <- comp_b_ms$stat_W2
      boot_ms_A2[valid_count] <- comp_b_ms$stat_A2
    }
    if (transform %in% c("both", "malmquist")) {
      boot_mal_W2[valid_count] <- comp_b_mal$stat_W2
      boot_mal_A2[valid_count] <- comp_b_mal$stat_A2
    }
  }

  if (valid_count == 0) {
    stop("All bootstrap replicates failed during MLE estimation or standardization.")
  }

  p_vals <- list()
  if (transform %in% c("both", "ms")) {
    p_vals$mW2 <- mean(boot_ms_W2[1:valid_count] >= obs_ms$stat_W2)
    p_vals$mA2 <- mean(boot_ms_A2[1:valid_count] >= obs_ms$stat_A2)
  }
  if (transform %in% c("both", "malmquist")) {
    p_vals$lW2 <- mean(boot_mal_W2[1:valid_count] >= obs_mal$stat_W2)
    p_vals$lA2 <- mean(boot_mal_A2[1:valid_count] >= obs_mal$stat_A2)
  }

  list(
    p_values = p_vals,
    valid_replicates = valid_count,
    obs_ms = obs_ms,
    obs_malmquist = obs_mal
  )
}
