
#' PCA-Based Slow Digestibility Index
#'
#' Computes the PCA-based slow digestibility index using only principal
#' components with eigen values greater than 1.
#'
#' @param Data A data frame or object coercible to a data frame. The first
#'   column must contain candidate names. The remaining numeric columns must
#'   follow this sequence: TS %, Aratio, TAC%, TAPC%, RDS %, SDS%, RS%, IGP%,
#'   RC%, Total Protein, Total Oil, Total Phenolic, PV, PT, HS, and FV.
#' @param type A character vector containing `+` and `-` signs to indicate
#'   benefit and cost criteria, respectively. Its length must match the number
#'   of criteria columns.
#'
#' @return A list with three components:
#' \describe{
#'   \item{SelectedPC}{A data frame containing the selected principal components,
#'   their eigen values, and variance proportions.}
#'   \item{PCAWeight}{A data frame containing PCA-derived weights for each criterion.}
#'   \item{Index}{A data frame containing normalized score and rank for each candidate.}
#' }
#'
#' @details The function first transforms cost criteria into benefit form, then
#'   standardizes the data and performs principal component analysis. Only those
#'   principal components with eigen values greater than 1 are retained. The
#'   criterion weights are derived from the absolute loadings weighted by the
#'   proportion of explained variance of the selected components. The final
#'   candidate score is min-max normalized and ranked in descending order.
#'
#'@references
#'Pandey, S., Goswami, D., Vinutha, T., Goswami, S., Kumar, R. R., Singh, S. P., ... & Krishnan, V. (2026). Molecular and microstructural cues for starch digestive heterogeneity in Indian pearl millet (Pennisetum Glaucum). Journal of Functional Foods, 138, 107208.
#' @examples
#' \donttest{
#' simulate_new_crop_data <- function(n_rep = 20, seed = 123) {
#' crop_names <- c("Sample 1", "Sample 2", "Sample 3", "Sample 4", "Sample 5")
#'  sim_one_crop <- function(crop, n) {
#'    data.frame(
#'      Crop = rep(crop, n),
#'      `TS %` = runif(n, 40, 80),
#'      Aratio = runif(n, 0.30, 2.50),
#'      `TAC%` = runif(n, 20, 35),
#'      `TAPC%` = runif(n, 10, 60),
#'      `RDS %` = runif(n, 35, 75),
#'      `SDS%` = runif(n, 5, 25),
#'      `RS%` = runif(n, 10, 45),
#'      `IGP%` = runif(n, 65, 100),
#'      `RC%` = runif(n, 15, 35),
#'      `Total Protein` = runif(n, 5, 25),
#'      `Total Oil` = runif(n, 1, 10),
#'      `Total Phenolic` = runif(n, 0.5, 7.5),
#'      PV = runif(n, 800, 6000),
#'      PT = runif(n, 60, 75),
#'      HS = runif(n, 700, 5000),
#'      FV = runif(n, 1500, 9000),
#'      check.names = FALSE
#'    )
#'  }
#'  simulated_data <- do.call(
#'    rbind,
#'    lapply(crop_names, sim_one_crop, n = n_rep)
#'  )
#'  numeric_cols <- setdiff(names(simulated_data), "Crop")
#'  simulated_data[numeric_cols] <- round(simulated_data[numeric_cols], 3)
#'   rownames(simulated_data) <- NULL
#'   simulated_data
#' }
#' Data <- simulate_new_crop_data(n_rep = 1, seed = 123)
#' tp <- c("+", "+", "+", "-", "-", "+", "+", "-", "+", "+", "+", "+", "-", "+", "+", "+")
#' pcaSDI(Data, type = tp)
#' }
#' @export
#'
pcaSDI <- function(Data, type) {

  Data <- as.data.frame(Data)

  if (ncol(Data) < 2) {
    stop("Data must contain at least one candidate column and one numeric variable column.")
  }

  candidate<-NULL
  colnames(Data)[1] <- "candidate"

  decision_data <- Data[, -1, drop = FALSE]

  if (!all(sapply(decision_data, is.numeric))) {
    stop("All criteria columns must be numeric.")
  }

  if (length(type) != ncol(decision_data)) {
    stop("Length of type must be equal to the number of criteria columns.")
  }

  if (!all(type %in% c("+", "-"))) {
    stop("type must contain only '+' and '-'.")
  }

  adjusted_data <- decision_data

  for (j in seq_len(ncol(adjusted_data))) {
    if (type[j] == "-") {
      adjusted_data[, j] <- max(adjusted_data[, j], na.rm = TRUE) - adjusted_data[, j]
    }
  }

  if (any(apply(adjusted_data, 2, sd, na.rm = TRUE) == 0)) {
    stop("One or more criteria columns have zero variance.")
  }

  scaled_data <- scale(adjusted_data)

  pca_result <- prcomp(scaled_data, center = FALSE, scale. = FALSE)

  eigen_values <- pca_result$sdev^2
  selected_pc <- which(eigen_values > 1)

  if (length(selected_pc) == 0) {
    stop("No principal component has eigen value greater than 1.")
  }

  selected_eigen <- eigen_values[selected_pc]
  selected_rotation <- pca_result$rotation[, selected_pc, drop = FALSE]
  selected_scores <- pca_result$x[, selected_pc, drop = FALSE]

  variance_prop <- selected_eigen / sum(selected_eigen)

  weighted_loadings <- abs(selected_rotation) %*% variance_prop
  weights <- as.vector(weighted_loadings / sum(weighted_loadings))

  candidate_scores <- as.matrix(scaled_data) %*% weights
  candidate_scores <- as.vector(candidate_scores)

  min_max_norm <- function(x) {
    if (max(x) == min(x)) {
      return(rep(0, length(x)))
    }
    (x - min(x)) / (max(x) - min(x))
  }

  final_score <- min_max_norm(candidate_scores)
  final_rank <- rank(-final_score, ties.method = "min")

  Index <- data.frame(
    Score = round(final_score, 3),
    Rank = final_rank
  )

  rownames(Index) <- as.character(Data$candidate)

  PCAWeight <- data.frame(
    Criteria = colnames(decision_data),
    Weight = round(weights, 4)
  )

  SelectedPC <- data.frame(
    PC = paste0("PC", selected_pc),
    EigenValue = round(selected_eigen, 4),
    VarianceProportion = round(variance_prop, 4)
  )

  return(list(SelectedPC = SelectedPC, PCAWeight = PCAWeight, Index = Index))
}



