# This R script will take 
# 1) an expression matrix, 
# 2) a Silhouette Clusters Function file, 
# 3) list of differentially expressed genes along with stats and 
# 4) GO enrichment stats to generate a CSV file with list of functional groups and representative genes.

# ===================================================================
# Cluster Summary Script with GO Enrichment Integration
# ===================================================================

# Load libraries
library(dplyr)
library(readxl)
library(cluster)
library(openxlsx)
library(stringr)

# -------------------------------------------------------------------
# Function: summarize_clusters_with_GO (multi-DEG version, strict reps)
# -------------------------------------------------------------------
summarize_clusters_with_GO <- function(
    expr_mat,                   # numeric matrix/array: rows=genes, cols=samples
    annot_xlsx,                 # Excel with Gene_ID + Silhouette_Cluster (+ Function if available)
    deg_files,                  # character vector: one or more DEG .tsv files
    go_folder = "GO_files",     # folder containing GO_Enrichment_Cluster_X.csv
    figure_label = "LeafBlue+LeafRed; Common DEGs",
    blue_pattern = "Root_Blue", # regex for blue samples
    red_pattern  = "Root_Red",  # regex for red samples
    sentinel_floor = -3.231646,
    n_funcs = 3,
    n_reps  = 3
){
  stopifnot(is.matrix(expr_mat) || is.array(expr_mat))
  expr <- expr_mat
  
  # --- Clean expression
  expr[expr == sentinel_floor] <- NA
  expr <- expr[rowSums(!is.na(expr)) > 0, , drop = FALSE]
  expr <- expr[complete.cases(expr), , drop = FALSE]
  expr_scaled <- scale(expr)
  
  # --- Detect Blue vs Red columns
  blue_cols <- grep(blue_pattern, colnames(expr_scaled), value = TRUE)
  red_cols  <- grep(red_pattern,  colnames(expr_scaled), value = TRUE)
  if (length(blue_cols) == 0 || length(red_cols) == 0) {
    stop("Could not find Blue or Red columns. Check blue_pattern/red_pattern.")
  }
  
  # --- Read annotation
  annot <- readxl::read_excel(annot_xlsx)
  id_col <- intersect(names(annot), c("Gene_ID","Gene","transcript_id","Gene stable ID"))[1]
  names(annot)[names(annot) == id_col] <- "Gene_ID"
  clust_col <- intersect(names(annot), c("Silhouette_Cluster","Cluster"))[1]
  names(annot)[names(annot) == clust_col] <- "Silhouette_Cluster"
  func_col <- intersect(names(annot), c("Function","Annotation","Description"))[1]
  if (!is.na(func_col)) {
    names(annot)[names(annot) == func_col] <- "Function"
  } else {
    annot$Function <- NA_character_
  }
  annot <- annot %>% dplyr::select(Gene_ID, Silhouette_Cluster, Function)
  
  # --- Read and intersect multiple DEG tables
  deg_list <- lapply(deg_files, function(f) {
    d <- read.delim(f, stringsAsFactors = FALSE)
    if (!"Gene_ID" %in% names(d)) names(d)[1] <- "Gene_ID"
    if (!"log2FC" %in% names(d)) d$log2FC <- NA_real_
    if (!"FDR" %in% names(d))   d$FDR   <- NA_real_
    d
  })
  
  # find common genes across all DEG files
  common_genes <- Reduce(intersect, lapply(deg_list, function(x) x$Gene_ID))
  
  # restrict each DEG table to common genes
  deg_list <- lapply(seq_along(deg_list), function(i) {
    d <- deg_list[[i]]
    d <- d[d$Gene_ID %in% common_genes, ]
    names(d)[names(d) == "log2FC"] <- paste0("log2FC_", i)
    names(d)[names(d) == "FDR"]    <- paste0("FDR_", i)
    d
  })
  
  # merge all into one big DEG table
  deg <- Reduce(function(x, y) dplyr::full_join(x, y, by="Gene_ID"), deg_list)
  
  # --- Align annotation with expr
  genes_in_both <- intersect(rownames(expr_scaled), annot$Gene_ID)
  annot_filt <- annot %>% dplyr::filter(Gene_ID %in% genes_in_both)
  annot_filt <- annot_filt[match(rownames(expr_scaled), annot_filt$Gene_ID), ]
  keep <- !is.na(annot_filt$Silhouette_Cluster)
  expr_scaled <- expr_scaled[keep, , drop = FALSE]
  annot_filt  <- annot_filt[keep, , drop = FALSE]
  
  # --- Silhouette with pre-assigned cluster labels
  cl_vec <- as.integer(factor(annot_filt$Silhouette_Cluster))
  d <- dist(expr_scaled)
  sil <- cluster::silhouette(cl_vec, d)
  
  sil_df <- data.frame(
    Gene_ID          = rownames(expr_scaled),
    Cluster          = sil[, "cluster"],
    Neighbor_Cluster = sil[, "neighbor"],
    Silhouette_Width = sil[, "sil_width"],
    stringsAsFactors = FALSE
  )
  
  # --- Merge DEG + annotation
  merged <- sil_df %>%
    dplyr::left_join(annot_filt, by = "Gene_ID") %>%
    dplyr::left_join(deg, by = "Gene_ID")
  
  # --- Compute highlights (Blue vs Red mean expression)
  merged$mean_blue <- rowMeans(expr_scaled[, blue_cols, drop = FALSE], na.rm = TRUE)
  merged$mean_red  <- rowMeans(expr_scaled[, red_cols,  drop = FALSE], na.rm = TRUE)
  
  cluster_delta <- merged %>%
    dplyr::group_by(Cluster) %>%
    dplyr::summarize(
      Delta_Blue_minus_Red = mean(mean_blue - mean_red, na.rm = TRUE),
      IQR_within = IQR(c(mean_blue, mean_red), na.rm = TRUE),
      .groups = "drop"
    ) %>%
    dplyr::mutate(Cluster_Highlights = dplyr::case_when(
      Delta_Blue_minus_Red >=  0.25 ~ "Upregulated in Blue",
      Delta_Blue_minus_Red <= -0.25 ~ "Upregulated in Red",
      TRUE ~ ifelse(IQR_within >= 0.5, "Variable expression", "Balanced/low-shift")
    ))
  
  # --- Stats
  cluster_stats <- merged %>%
    dplyr::group_by(Cluster) %>%
    dplyr::summarize(
      Num_Genes = dplyr::n(),
      Avg_Silhouette = mean(Silhouette_Width, na.rm = TRUE),
      .groups = "drop"
    )
  
  # --- Functional groups
  func_summary <- merged %>%
    dplyr::filter(!is.na(Function) & Function != "") %>%
    dplyr::count(Cluster, Function, sort = TRUE) %>%
    dplyr::group_by(Cluster) %>%
    dplyr::slice_head(n = n_funcs) %>%
    dplyr::summarize(Functional_Groups = paste(Function, collapse = "; "), .groups = "drop")
  
  # --- GO terms
  go_summary <- list()
  for (cl in unique(merged$Cluster)) {
    go_file <- file.path(go_folder, paste0("GO_Enrichment_Cluster_", cl, ".csv"))
    if (file.exists(go_file)) {
      go <- read.csv(go_file, stringsAsFactors = FALSE)
      if (all(c("Description","p.adjust") %in% names(go))) {
        top_terms <- go %>% dplyr::arrange(p.adjust) %>% head(n_funcs)
        go_summary[[as.character(cl)]] <- paste(top_terms$Description, collapse = "; ")
      }
    }
  }
  go_summary_df <- tibble::tibble(Cluster = as.integer(names(go_summary)), GO_Terms = unlist(go_summary))
  
  # --- Representative genes (strict filter across all DEG files)
  rep_candidates <- merged %>%
    dplyr::filter(
      apply(dplyr::select(., dplyr::starts_with("log2FC_")), 1,
            function(x) all(abs(x) > 2, na.rm = TRUE)) &
        apply(dplyr::select(., dplyr::starts_with("FDR_")), 1,
              function(x) all(x < 0.1, na.rm = TRUE))
    )
  
  reps <- rep_candidates %>%
    dplyr::arrange(Cluster,
                   dplyr::desc(Silhouette_Width)) %>%
    dplyr::group_by(Cluster) %>%
    dplyr::slice_head(n = n_reps) %>%
    dplyr::summarize(
      Representative_Gene_IDs = paste(Gene_ID, collapse = "; "),
      .groups = "drop"
    )
  
  # --- Final table
  final <- cluster_stats %>%
    dplyr::left_join(cluster_delta %>% dplyr::select(Cluster, Cluster_Highlights), by = "Cluster") %>%
    dplyr::left_join(func_summary, by = "Cluster") %>%
    dplyr::left_join(go_summary_df, by = "Cluster") %>%
    dplyr::left_join(reps, by = "Cluster") %>%
    dplyr::mutate(Figure = figure_label, .before = 1) %>%
    dplyr::arrange(Cluster)
  
  # --- Save
  out_xlsx <- paste0(gsub("[^A-Za-z0-9]+", "_", figure_label), "_Summary_with_GO.xlsx")
  openxlsx::write.xlsx(list(
    Cluster_Table = final,
    PerGene_All   = merged %>% dplyr::arrange(Cluster, dplyr::desc(Silhouette_Width)),
    Silhouette_PerGene = sil_df
  ), out_xlsx, row.names = FALSE)
  
  message("Wrote: ", out_xlsx)
  return(final)
}

# -------------------------------------------------------------------
# Example Usage
# -------------------------------------------------------------------
# load("PDF54_edgeR_analysis.RData")

final_common <- summarize_clusters_with_GO(
  expr_mat   = heatmap_RootBlue_RootRed,
  annot_xlsx = "AR_Blue_AR_Red Silhouette Clusters Function.xlsx",
  deg_files  = c("DEG AR_Blue Flt vs. Gnd.tsv",
                 "DEG AR_Red Flt vs. Gnd.tsv"),
  go_folder  = "AR_Blue_AR_Red",
  figure_label = "Common_DEGs_AR_Blue_AR_Red")
