#' Dunnett's Test for Differential Gene Expression
#'
#' Performs Dunnett's multiple comparison test (control vs. treatment) for every
#' gene (row) in the expression matrix using \code{\link[DescTools]{DunnettTest}},
#' applies BH correction, and returns a results table with the list of significant
#' DEGs.  Genes with insufficient variance, missing values, or other numerical
#' issues are skipped gracefully and receive \code{NA} p-values.
#'
#' @inheritParams perform_t_test
#'
#' @return A named list:
#'   \describe{
#'     \item{Table}{Data.frame with columns \code{G_Symbol}, \code{log2FC},
#'       \code{p.value}, \code{BH}, \code{fdr}.}
#'     \item{DEGs}{Data.frame of significant gene identifiers.}
#'   }
#'
#' @export
#' @importFrom DescTools DunnettTest
#' @importFrom stats p.adjust na.omit quantile var
#' @examples
#' library(DGEAR)
#' data("gene_exp_data")
#' result <- perform_dunnett_test(dataframe = gene_exp_data,
#'                                con1 = 1, con2 = 10,
#'                                exp1 = 11, exp2 = 20)
#' head(result$Table)
#' result$DEGs
perform_dunnett_test <- function(dataframe, con1, con2, exp1, exp2,
                                 alpha = 0.05, annot_df = NULL) {
  prep     <- .prepare_data(dataframe, con1, con2, exp1, exp2)
  G_Symbol <- .resolve_symbols(prep$dataframe, annot_df)
  df_work  <- prep$dataframe
  log2FC   <- prep$log2FC
  
  group <- factor(c(rep("con", con2 - con1 + 1L),
                    rep("tre", exp2 - exp1 + 1L)))
  
  df_t <- t(as.matrix(df_work))  # samples × genes
  
  p.values <- vapply(seq_len(ncol(df_t)), function(i) {
    x <- as.numeric(df_t[, i])
    # Defensive: skip genes with NA, Inf, zero-variance, or too few finite obs
    if (any(!is.finite(x)) || var(x, na.rm = TRUE) == 0 ||
        sum(is.finite(x)) < length(levels(group))) {
      return(NA_real_)
    }
    tryCatch({
      d <- DescTools::DunnettTest(x, group)
      as.numeric(d$con[, 4L])
    }, error = function(e) NA_real_,
    warning = function(w) {
      suppressWarnings({
        d <- DescTools::DunnettTest(x, group)
        as.numeric(d$con[, 4L])
      })
    })
  }, numeric(1L))
  
  d_stat         <- data.frame(G_Symbol, log2FC, p.value = p.values,
                               stringsAsFactors = FALSE)
  d_stat$BH      <- p.adjust(d_stat$p.value, method = "BH")
  d_stat$fdr     <- as.integer(!is.na(d_stat$BH) & d_stat$BH <= alpha)
  
  DEGs <- data.frame(DEGs = na.omit(d_stat$G_Symbol[d_stat$fdr == 1L]),
                     stringsAsFactors = FALSE)
  list(Table = d_stat, DEGs = DEGs)
}
