#' Sensitivity Grid of Process Capability Indices
#'
#' Computes a PCI across a grid of parameter values (short-term standard
#' deviation \code{sigma}, long-term standard deviation \code{s}, and/or
#' desired yield \code{p0}), optionally with bootstrap confidence intervals at
#' multiple significance levels.
#'
#' @param index Character: one of the 12 index names (see \code{\link{pci}}).
#' @param dist A \code{\link{pci_dist}} object (required for \code{"Cpy"}).
#' @param LSL,USL Specification limits.
#' @param target Target value (for \code{Cpm}/\code{Cpmk}).
#' @param sigma_vals Numeric vector of \eqn{\sigma} values to sweep
#'   (for capability indices).
#' @param s_vals Numeric vector of \eqn{s} values to sweep
#'   (for performance indices).
#' @param p0_vals Numeric vector of \eqn{p_0} values to sweep (for \code{Cpy}).
#' @param mu Short-term process mean.
#' @param xbar Long-term process mean.
#' @param alpha_vals Numeric vector of significance levels.
#'   Default \code{c(0.10, 0.05, 0.01)}.
#' @param n Sample size for bootstrap CIs. If \code{NULL}, CIs are omitted.
#' @param B Bootstrap replications. Default 2000.
#'
#' @return A \code{data.frame} (with additional class \code{"pci_grid"})
#'   in long format with columns:
#'   \code{index}, \code{sigma}, \code{s}, \code{p0}, \code{alpha},
#'   \code{estimate}, \code{lower}, \code{upper}.
#'   Columns that do not apply to the chosen index contain \code{NA}.
#'
#' @examples
#' grid <- pci_grid("Cp", LSL = 57, USL = 63,
#'                  sigma_vals = c(0.5, 1.0, 1.5),
#'                  mu = 60, alpha_vals = c(0.05, 0.01))
#' print(grid)
#'
#' @seealso \code{\link{pci}}, \code{\link{pci_ci}},
#'   \code{\link{plot.pci_grid}}
#' @export
pci_grid <- function(index,
                     dist       = NULL,
                     LSL        = NULL, USL  = NULL, target = NULL,
                     sigma_vals = NULL,
                     s_vals     = NULL,
                     p0_vals    = NULL,
                     mu         = NULL, xbar = NULL,
                     alpha_vals = c(0.10, 0.05, 0.01),
                     n          = NULL,
                     B          = 2000) {

  valid_indices <- c("Cp", "Cpk", "Cpu", "Cpl", "Cpm", "Cpmk",
                     "Pp", "Ppk", "Ppu", "Ppl", "Z", "Cpy")
  index <- match.arg(index, valid_indices)

  # Determine which sweep variable applies
  capability_idx  <- c("Cp", "Cpk", "Cpu", "Cpl", "Cpm", "Cpmk", "Z")
  performance_idx <- c("Pp", "Ppk", "Ppu", "Ppl")

  # Build the sweep vectors
  if (index %in% capability_idx) {
    sweep_var <- "sigma"
    sweep_vals <- if (!is.null(sigma_vals)) sigma_vals else {
      if (!is.null(s_vals)) s_vals else 1
    }
  } else if (index %in% performance_idx) {
    sweep_var <- "s"
    sweep_vals <- if (!is.null(s_vals)) s_vals else {
      if (!is.null(sigma_vals)) sigma_vals else 1
    }
  } else {
    # Cpy
    sweep_var <- "p0"
    sweep_vals <- if (!is.null(p0_vals)) p0_vals else 0.95
  }

  # Build the result rows
  rows <- list()
  row_idx <- 0L

  for (sv in sweep_vals) {
    # Compute point estimate
    est <- tryCatch({
      switch(sweep_var,
        sigma = pci(index, dist = dist, LSL = LSL, USL = USL, target = target,
                    mu = mu, sigma = sv, xbar = xbar, s = sv),
        s     = pci(index, dist = dist, LSL = LSL, USL = USL, target = target,
                    mu = mu, sigma = sv, xbar = xbar, s = sv),
        p0    = pci(index, dist = dist, LSL = LSL, USL = USL, target = target,
                    mu = mu, sigma = NULL, xbar = xbar, s = NULL,
                    p0 = sv)
      )
    }, error = function(e) NA_real_)

    for (av in alpha_vals) {
      # Compute CI if n is supplied
      ci_lower <- NA_real_
      ci_upper <- NA_real_

      if (!is.null(n) && !is.null(dist)) {
        tryCatch({
          ci_obj <- pci_ci(index = index, dist = dist, n = n,
                           LSL = LSL, USL = USL, target = target,
                           LDL = NULL, UDL = NULL,
                           p0 = if (sweep_var == "p0") sv else NULL,
                           alpha = av, B = B)
          ci_lower <- ci_obj$lower
          ci_upper <- ci_obj$upper
        }, error = function(e) {
          # Leave as NA
        })
      }

      row_idx <- row_idx + 1L
      rows[[row_idx]] <- data.frame(
        index    = index,
        sigma    = if (sweep_var == "sigma") sv else NA_real_,
        s        = if (sweep_var == "s")     sv else NA_real_,
        p0       = if (sweep_var == "p0")    sv else NA_real_,
        alpha    = av,
        estimate = est,
        lower    = ci_lower,
        upper    = ci_upper,
        stringsAsFactors = FALSE
      )
    }
  }

  result <- do.call(rbind, rows)
  rownames(result) <- NULL

  structure(result, class = c("pci_grid", "data.frame"))
}
