#' @title Initialize GSEA Environment Object

#' @description Unified entry point supporting limma-voom (no intercept design) and DESeq2 objects.

#' Automatically extracts contrasts, differential analysis results, and expression matrices to generate

#' a standardized GseaEnv object.

#' @param fit Differential analysis object. Supports \code{MArrayLM} (limma) or \code{DESeqDataSet} (DESeq2).

#' @param pathway_obj Gene set object. Typically generated by \code{build_gsea_pathways()}.

#' @param expr_data Optional. Expression matrix or DGEList. If NULL, extraction from fit object will be attempted (partial support only).

#' @param target_factor Only for DESeq2. Specifies the target factor of interest. If NULL, automatically inferred as the last term in the design formula.


#' @param verbose Logical. If TRUE (default), print progress messages. Set to FALSE for silent batch-mode use.
#' @return Returns a standardized object of class \code{GseaEnv}.

#' @export

#' @examples

#' # Limma-voom workflow using pre-computed inputs shipped with the package

#' data(preprocessed_limma, package = "GSEAlens")
#'
#' precomp <- preprocessed_limma

#' data(gsea_pathwaysets_toy, package = "GSEAlens")
#'
#' pathways <- gsea_pathwaysets_toy

#' env <- setup_gsea_env(

#'   fit       = precomp$fit,

#'   pathway_obj = pathways,

#'   expr_data = precomp$gsea_limma_voom_data

#' )

#' class(env)

setup_gsea_env <- function(fit, pathway_obj, expr_data = NULL, target_factor = NULL,
                                                    verbose = TRUE) {

    # IRON FIX (2026-07-01, D-2): add `verbose` to allow silent batch-mode use.
    if (isTRUE(verbose)) message("\nStarting GSEAlens engine...")



    # 1. 校验基因集对象

    if (is.null(pathway_obj) || is.null(pathway_obj$TERM2GENE)) {

    stop("Invalid pathway_obj! Please use build_gsea_pathways() to generate a valid gene set object.")

    }



    # 2. 识别后端类型并分发提取

    backend_data <- NULL

    backend_info <- NULL



    if (inherits(fit, "MArrayLM")) {

    message("Detected input type: [Limma-Voom]")



    # 调用 Limma 提取器

    backend_data <- .extract_limma_data(fit, expr_data)



    backend_info <- list(

            backend = "limma_voom",

            input_class = "MArrayLM",

            design_formula = NULL, # Limma fit 对象通常不直接保留公式

            target_factor = NA

    )

    } else if (inherits(fit, "DESeqDataSet")) {

    message("Detected input type: [DESeq2]")



    # 调用 DESeq2 提取器

    backend_data <- .extract_deseq2_data(fit, target_factor)



    # 记录实际使用的 target_factor

    actual_factor <- if (is.null(target_factor)) {

            utils::tail(attr(terms(DESeq2::design(fit)), "term.labels"), 1)

    } else {

            target_factor

    }



    backend_info <- list(

            backend = "deseq2",

            input_class = "DESeqDataSet",

            design_formula = DESeq2::design(fit),

            target_factor = actual_factor

    )

    } else {

    stop("Unsupported input type! Please provide MArrayLM (limma) or DESeqDataSet (DESeq2) object.")

    }



    # 3. 组装基因集信息

    #

    geneset_info <- list(

    name = pathway_obj$SuperTag %||% pathway_obj$name,

    term2gene = pathway_obj$TERM2GENE %||% pathway_obj$term2gene,

    meta_dict = {

            md <- pathway_obj$meta_dict %||% pathway_obj$TERM2NAME

            if (!"Subcollection" %in% colnames(md)) md$Subcollection <- ""

            if (!"Combo_Name" %in% colnames(md)) {

        md$Combo_Name <- ifelse(

                    is.na(md$Subcollection) | md$Subcollection == "",

                    md$Collection,

                    paste0(md$Collection, ":", md$Subcollection)

        )

            }

            if (!"Species" %in% colnames(md)) {

        md$Species <- pathway_obj$species %||% "HS"

            }

            md

    },

    used_collections = pathway_obj$collections_used %||% pathway_obj$used_collections,

    species = pathway_obj$species %||% "HS" # 新增

    )



    # 4. 构建最终对象

    env_obj <- create_gsea_env(

    backend_info = backend_info,

    contrast_registry = backend_data$contrast_registry,

    de_store = backend_data$de_store,

    expr_bundle = backend_data$expr_bundle,

    geneset = geneset_info,

    raw_obj = list(fit = fit) # 保留原始对象引用

    )



    # 5. 最终校验

    .check_gsea_env(env_obj)



    if (isTRUE(verbose)) {

    message("GseaEnv object built successfully!")

    message(sprintf("   Contains %d contrast groups", nrow(backend_data$contrast_registry)))

    message(sprintf("   Contains %d pathways", nrow(pathway_obj$meta_dict)))

    }



    return(env_obj)

}





# 查看函数





#' @title View GSEA Environment Object Overview

#' @description Print detailed information about the GseaEnv object to the console, including backend type,

#' contrast list, and gene set status.

#' @param env_obj GseaEnv object

#' @return Invisibly returns the input object (for chaining).

#' @export



#' @examples

#' # Build a GseaEnv from pre-computed inputs shipped with the package

#' data(preprocessed_limma, package = "GSEAlens")
#'
#' precomp <- preprocessed_limma

#' data(gsea_pathwaysets_toy, package = "GSEAlens")
#'
#' pathways <- gsea_pathwaysets_toy

#' env <- setup_gsea_env(

#'   fit       = precomp$fit,

#'   pathway_obj = pathways,

#'   expr_data = precomp$gsea_limma_voom_data

#' )

#' inspect_gsea_env(env)

inspect_gsea_env <- function(env_obj) {

    if (!inherits(env_obj, "GseaEnv")) stop("Input object is not of class GseaEnv.")



    # 解析信息

    bi <- env_obj$backend_info

    reg <- env_obj$contrast_registry

    gs <- env_obj$geneset

    expr <- env_obj$expr_bundle



    # 控制台输出

    message("")

    message(paste(rep("=", 60), collapse = ""))

    message("       GSEAlens Environment Summary")

    message(paste(rep("=", 60), collapse = ""))



    # 1. 后端信息

    message("[1] Backend Information")

    message(sprintf("   Type        : %s", bi$backend))

    message(sprintf("   Input Class : %s", bi$input_class))

    if (bi$backend == "deseq2") {

    message(sprintf("   Target Factor: %s", bi$target_factor))

    }

    message("")



    # 2. 对比组注册表

    message(sprintf("[2] Contrast Registry (%d comparisons)", nrow(reg)))

    if (nrow(reg) > 0) {

    # 打印前几个，防止刷屏

    print_head <- utils::head(reg[, c("contrast_id", "left_group", "right_group")], 5)

    for (i in seq_len(nrow(print_head))) {

            message(sprintf(

        "   [%d] %s  ( %s vs %s )",

        i, print_head$contrast_id[i],

        print_head$left_group[i], print_head$right_group[i]

            ))

    }

    if (nrow(reg) > 5) message("   ... (remaining omitted)")

    } else {

    message("   No contrasts detected!")

    }

    message("")



    # 3. 基因集信息

    message("[3] Gene Set Database")

    message(sprintf("   Name        : %s", gs$name))

    message(sprintf("   Pathways    : %d", nrow(gs$meta_dict)))

    message("")



    # 4. 表达数据状态

    message("[4] Expression Data Status")

    if (!is.null(expr$raw_counts)) {

    message(sprintf(

            "   Raw Counts  : %d genes x %d samples",

            nrow(expr$raw_counts), ncol(expr$raw_counts)

    ))

    message(sprintf("   Display Mat : %s", ifelse(!is.null(expr$display_expr), "Ready", "Missing")))

    } else {

    message("   Expression matrix not included (heatmap functionality will be unavailable)")

    }

    message("")



    # 5. 下一步指引

    message("[5] Next Step")

    message("   Please run the computation engine:")

    message("   > res <- batch_calc_gsea(env_obj)")

    message(paste(rep("=", 60), collapse = ""))



    invisible(env_obj)

}



#' @export

print.GseaEnv <- function(x, ...) {

    inspect_gsea_env(x)

}

