##' get_deg
##'
##' Do differential analysis according to an expression set and group
##' information.
##'
##' @inheritParams draw_pca
##' @inheritParams draw_volcano
##' @inheritParams trans_ensembl_exp
##' @param ids optional probe-to-symbol annotation table. If `NULL`, `exp` is
##'   treated as a gene-level matrix and no ID conversion is performed.
##' @param entriz whether to convert symbols to Entrez IDs
##' @return a deg data.frame
##' @author Xiaojie Sun
##' @importFrom limma lmFit
##' @importFrom limma eBayes
##' @importFrom limma topTable
##' @importFrom dplyr mutate
##' @importFrom dplyr inner_join
##' @export
##' @examples
##' \dontrun{
##' if(requireNamespace("Biobase",quietly = TRUE)&
##'    requireNamespace("AnnoProbe",quietly = TRUE)){
##'   gse = "GSE42872"
##'   a = geo_download(gse,destdir=tempdir())
##'   find_anno(geo$gpl)
##'   ids <- AnnoProbe::idmap(geo$gpl,destdir = tempdir())
##'   Group = rep(c("control","treat"),each = 3)
##'   Group = factor(Group)
##'   deg = get_deg(geo$exp,Group,ids,entriz = FALSE)
##'   head(deg)
##' }else{
##'   if(!requireNamespace("AnnoProbe",quietly = TRUE)) {
##'     warning("Package 'AnnoProbe' needed for this function to work.
##'          Please install it by install.packages('AnnoProbe')",call. = FALSE)
##'   }
##'   if(!requireNamespace("Biobase",quietly = TRUE)) {
##'     warning("Package 'Biobase' needed for this function to work.
##'          Please install it by BiocManager::install('Biobase')",call. = FALSE)
##'   }
##' }
##' }
##' @seealso
##' \code{\link{multi_deg}};\code{\link{get_deg_all}}

get_deg <- function(exp,
                    group_list,
                    ids = NULL,
                    logFC_cutoff=1,
                    pvalue_cutoff=0.05,
                    adjust = TRUE,
                    entriz = TRUE,
                    species = "human") {
  group_list <- .tinyarray_prepare_group_list_safe(group_list)
  if (is.null(group_list)) return(NULL)
  if(nlevels(group_list)==2){
    if(ncol(exp)!=length(group_list))stop("wrong group_list or exp")
    design=stats::model.matrix(~group_list)
    fit=lmFit(exp,design)
    fit=eBayes(fit)
    deg=topTable(fit,coef=2,number = Inf)

    if("ID" %in% colnames(deg)){
      deg$probe_id <- deg$ID
    }else{
      deg$probe_id <- rownames(deg)
    }
    if (is.null(ids)) {
      deg$symbol <- as.character(deg$probe_id)
    } else {
      if(ncol(ids)!=2)stop("wrong ids parameter, it should be a data.frame with probe_id and symbol")
      colnames(ids) = c("probe_id","symbol")
      if(!is.character(ids$probe_id)) ids$probe_id = as.character(ids$probe_id)
      ids = stats::na.omit(ids)
      ids = .tinyarray_dedup_by_key(ids,"symbol")
      deg <- inner_join(deg,ids,by="probe_id")
    }
    if(adjust){
      k1 = (deg$adj.P.Val < pvalue_cutoff)&(deg$logFC < -logFC_cutoff)
      k2 = (deg$adj.P.Val < pvalue_cutoff)&(deg$logFC > logFC_cutoff)
    }else{
      k1 = (deg$P.Value < pvalue_cutoff)&(deg$logFC < -logFC_cutoff)
      k2 = (deg$P.Value < pvalue_cutoff)&(deg$logFC > logFC_cutoff)
    }

    change = ifelse(k1,
                    "down",
                    ifelse(k2,
                           "up",
                           "stable"))
    deg$change <- change

    if(entriz){
      org = .tinyarray_orgdb_for_species(species)
      .tinyarray_require_clusterProfiler()
      s2e <- tryCatch({
        clusterProfiler::bitr(deg$symbol,fromType = "SYMBOL",toType = "ENTREZID",OrgDb = org$orgdb)
      },error = function(e){666})
      if(!is.character(s2e)){
        before_n <- nrow(deg)
        deg2 <- inner_join(deg,s2e,by=c("symbol"="SYMBOL"))
        if (nrow(deg2) < max(1L, floor(before_n * 0.1))) {
          warning(
            "Entrez ID conversion kept fewer than 10% of rows; please check the expression row names, ids, or species.",
            call. = FALSE
          )
        } else {
          deg <- deg2
          deg <- deg[!duplicated(deg$symbol),]
        }
      }else{
        warning("Entrez ID conversion failed, please check the previous warning.")
      }
    }
  }else{
    deg <-multi_deg(exp = exp,
                    group_list = group_list,
                    ids = ids,
                    logFC_cutoff = logFC_cutoff,
                    pvalue_cutoff = pvalue_cutoff,
                    adjust = adjust,
                    entriz = entriz,
                    species = species)
  }
  return(deg)
}
