aedl_validate_inputs <- function(yi, vi, alpha, side, a, b, t_grid, nsim,
                                 nsim_chi, n_tau, I2_grid, normalize_cdf) {
  if (!is.numeric(yi) || !is.numeric(vi)) {
    stop("yi and vi must be numeric vectors.", call. = FALSE)
  }
  if (length(yi) != length(vi)) {
    stop("yi and vi must have the same length.", call. = FALSE)
  }
  if (length(yi) < 2) {
    stop("At least two studies are required.", call. = FALSE)
  }
  if (anyNA(yi) || anyNA(vi)) {
    stop("yi and vi must not contain missing values.", call. = FALSE)
  }
  if (any(!is.finite(yi)) || any(!is.finite(vi))) {
    stop("yi and vi must contain only finite values.", call. = FALSE)
  }
  if (any(vi <= 0)) {
    stop("All vi must be positive.", call. = FALSE)
  }
  if (!is.numeric(alpha) || length(alpha) != 1 || alpha <= 0 || alpha >= 1) {
    stop("alpha must be a single number between 0 and 1.", call. = FALSE)
  }
  if (!(side %in% c(1, 2))) {
    stop("side must be 1 or 2.", call. = FALSE)
  }
  if (a < 0 || b > 1 || a >= b) {
    stop("a and b must satisfy 0 <= a < b <= 1.", call. = FALSE)
  }
  if (!is.numeric(t_grid) || length(t_grid) < 2 || any(!is.finite(t_grid))) {
    stop("t_grid must be a finite numeric vector with length at least 2.",
         call. = FALSE)
  }
  if (is.unsorted(t_grid, strictly = TRUE)) {
    stop("t_grid must be strictly increasing.", call. = FALSE)
  }
  if (!is.numeric(I2_grid) || length(I2_grid) < 2 ||
      any(!is.finite(I2_grid))) {
    stop("I2_grid must be a finite numeric vector with length at least 2.",
         call. = FALSE)
  }
  if (is.unsorted(I2_grid, strictly = TRUE) ||
      min(I2_grid) < 0 || max(I2_grid) >= 1) {
    stop("I2_grid must be strictly increasing and lie in [0, 1).",
         call. = FALSE)
  }
  if (!is_count(nsim) || !is_count(nsim_chi) || !is_count(n_tau)) {
    stop("nsim, nsim_chi, and n_tau must be positive whole numbers.",
         call. = FALSE)
  }
  if (!is.logical(normalize_cdf) || length(normalize_cdf) != 1 ||
      is.na(normalize_cdf)) {
    stop("normalize_cdf must be TRUE or FALSE.", call. = FALSE)
  }

  invisible(TRUE)
}

aedl_new_result <- function(x, call, method) {
  required <- c(
    "estimate", "se", "ci.lb", "ci.ub", "pval", "tau2", "tau2_for_dist",
    "I2hat", "I2c", "tau2c", "crit"
  )
  missing <- setdiff(required, names(x))
  if (length(missing) > 0) {
    stop(
      "Internal aedl result is missing: ",
      paste(missing, collapse = ", "),
      call. = FALSE
    )
  }

  x$method <- method
  x$call <- call
  class(x) <- "aedl"
  x
}

aedl_dl_summary <- function(yi, vi) {
  K <- length(vi)
  s1 <- sum(1 / vi)
  s2 <- sum(1 / vi^2)
  denom <- s1 - s2 / s1
  sig2t <- (K - 1) * s1 / (s1^2 - s2)

  theta_fixed <- sum(yi / vi) / s1
  Q <- sum((yi - theta_fixed)^2 / vi)
  tau2dl0 <- (Q - (K - 1)) / denom
  tau2dl <- max(0, tau2dl0)
  weights_dl <- 1 / (vi + tau2dl)

  estimate <- sum(weights_dl * yi) / sum(weights_dl)
  se <- 1 / sqrt(sum(weights_dl))
  I2hat <- tau2dl / (sig2t + tau2dl)

  list(
    K = K,
    s1 = s1,
    s2 = s2,
    denom = denom,
    sig2t = sig2t,
    Q = Q,
    tau2dl0 = tau2dl0,
    tau2 = tau2dl,
    estimate = estimate,
    se = se,
    I2hat = I2hat,
    zval = estimate / se
  )
}

aedl_validate_density_inputs <- function(vi, tau2, t_grid = NULL, nsim = NULL,
                                         nsim_chi = 100000, n_tau = 1000) {
  if (!is.numeric(vi) || length(vi) < 2) {
    stop("vi must be a numeric vector with length at least 2.", call. = FALSE)
  }
  if (anyNA(vi) || any(!is.finite(vi)) || any(vi <= 0)) {
    stop("vi must contain only positive finite values.", call. = FALSE)
  }
  if (!is.numeric(tau2) || length(tau2) != 1 || is.na(tau2) ||
      !is.finite(tau2) || tau2 < 0) {
    stop("tau2 must be a single non-negative finite number.", call. = FALSE)
  }
  if (!is.null(t_grid)) {
    if (!is.numeric(t_grid) || length(t_grid) < 2 ||
        anyNA(t_grid) || any(!is.finite(t_grid))) {
      stop("t_grid must be a finite numeric vector with length at least 2.",
           call. = FALSE)
    }
  }
  if (!is.null(nsim) && !is_count(nsim)) {
    stop("nsim must be a positive whole number.", call. = FALSE)
  }
  if (!is_count(nsim_chi) || !is_count(n_tau)) {
    stop("nsim_chi and n_tau must be positive whole numbers.",
         call. = FALSE)
  }

  invisible(TRUE)
}

is_count <- function(x) {
  is.numeric(x) && length(x) == 1 && is.finite(x) && x >= 1 && x == as.integer(x)
}
