
#' Compute sex-specific differentially expressed genes (DEGs) per category
#' @description
#' Identifies male-specific, female-specific, sex-dimorphic, and sex-neutral DEGs from differential expression results. 
#' "sex-modulated" requires the interaction mode and is not identified by categorize_sex.
#'
#' @param male_degs Data frame containing male differential expression results from one specific cell-type or bulk dataset.
#' @param female_degs Data frame containing female differential expression results from one specific cell-type or bulk dataset.
#' @param alpha Numeric. FDR threshold for significance.
#' @param beta Numeric. P-value threshold for excluding genes in opposite sex.
#' @param min_abs_logfc Numeric. Minimum absolute log2 fold change threshold.
#'
#' @return Data frame containing categorized DEGs with associated statistics.
#'
#'
#' @export
#'

categorize_sex <- function(male_degs,
                           female_degs,
                           alpha = 0.05,
                           beta = 0.5,
                           min_abs_logfc = 0.25) {
  
  
  
  required_cols <- c("p_val_adj", "p_val", "avg_log2FC")
  
  missing_male <- setdiff(required_cols, colnames(male_degs))
  missing_female <- setdiff(required_cols, colnames(female_degs))
  
  if (length(missing_male) > 0) {
    stop(paste("Male DEG table is missing columns:",
               paste(missing_male, collapse = ", ")))
  }
  
  if (length(missing_female) > 0) {
    stop(paste("Female DEG table is missing columns:",
               paste(missing_female, collapse = ", ")))
  }
  
  
  # Helper function to extract logFC and FDR values
  get_deg_stats <- function(genes, deg_data) {
    matched_idx <- match(genes, rownames(deg_data))
    list(
      logFC = deg_data[matched_idx, "avg_log2FC"],
      fdr = deg_data[matched_idx, "p_val_adj"]
    )
  }
  
  # Identify male-specific genes
  male_candidates <- rownames(male_degs)[male_degs$p_val_adj < alpha]
  
  f_pval <- female_degs[match(male_candidates, rownames(female_degs)), "p_val"]
  
  male_specific <- male_candidates[is.na(f_pval) | f_pval > beta]
  
  male_specific <- male_specific[
    abs(male_degs[match(male_specific, rownames(male_degs)), "avg_log2FC"]) > min_abs_logfc
  ]
  
  
  # Identify female-specific genes
  female_candidates <- rownames(female_degs)[female_degs$p_val_adj < alpha]
  
  m_pval <- male_degs[match(female_candidates, rownames(male_degs)), "p_val"]
  
  female_specific <- female_candidates[is.na(m_pval) | m_pval > beta]
  
  female_specific <- female_specific[
    abs(female_degs[match(female_specific, rownames(female_degs)), "avg_log2FC"]) > min_abs_logfc
  ]
  
  # Identify shared and dimorphic genes
  dimorphic_genes <- NULL
  shared_genes <- NULL
  intersecting_genes <- intersect(male_candidates, female_candidates)
  
  if (length(intersecting_genes) > 0) {
    logfc_male <- male_degs[match(intersecting_genes, rownames(male_degs)),]$avg_log2FC
    logfc_female <- female_degs[match(intersecting_genes, rownames(female_degs)),]$avg_log2FC
    
    dimorphic_indices <- intersect(which(sign(logfc_male) != sign(logfc_female)),
                                   intersect(which(abs(logfc_male) > min_abs_logfc),
                                             which(abs(logfc_female) > min_abs_logfc)))
    dimorphic_genes <- intersecting_genes[dimorphic_indices]
    
    shared_indices <- intersect(which(sign(logfc_male) == sign(logfc_female)),
                                intersect(which(abs(logfc_male) > min_abs_logfc),
                                          which(abs(logfc_female) > min_abs_logfc)))
    shared_genes <- intersecting_genes[shared_indices]
  }
  
  # Compile results into a data frame
  all_categories <- list(
    "male-specific" = male_specific,
    "female-specific" = female_specific,
    "sex-dimorphic" = dimorphic_genes,
    "sex-neutral" = shared_genes
  )
  
  results <- data.frame(
    DEG_Type = rep(names(all_categories), sapply(all_categories, length)),
    Gene_Symbols = unlist(all_categories),
    stringsAsFactors = FALSE
  )
  
  if (nrow(results) == 0) {
    return(results)
  }
  
  # Add male statistics
  male_stats <- get_deg_stats(results$Gene_Symbols, male_degs)
  results$Male_avg_logFC <- male_stats$logFC
  results$Male_FDR <- male_stats$fdr
  
  # Add female statistics
  female_stats <- get_deg_stats(results$Gene_Symbols, female_degs)
  results$Female_avg_logFC <- female_stats$logFC
  results$Female_FDR <- female_stats$fdr
  
  return(results)
}

