#' Perform Sex-Phenotype Interaction Analysis for Bulk Data
#'
#' @description Identifies genes whose expression is modulated by the interaction
#' between sex and phenotype using a differential difference contrast 
#'
#' @param expression_data Numeric matrix of expression data (features x samples).
#' @param phenotype Character or factor vector of sample phenotypes.
#' @param sex Character or factor vector of sample sexes.
#' @param phenotype_labels_vector Character vector of phenotype levels (default c("WT","TG")).
#' @param sex_labels_vector Character vector of sex levels (default c("F","M")).
#' @param min_logfc Numeric. Minimum absolute log fold change for reporting significant genes (default 0.25).
#' @param alpha Numeric. FDR threshold for significance (default 0.05).
#' @param min_samples Integer. Minimum number of samples per group (default 20).
#'
#' @return A list with all DE results, filtered significant DEGs, and summary statistics.
#'
#' @import limma
#' @importFrom stats model.matrix
#' @export
sex_interaction_analysis_bulk <- function(expression_data,
                                          phenotype,
                                          sex,
                                          phenotype_labels_vector = c("WT","TG"),
                                          sex_labels_vector = c("F","M"),
                                          min_logfc = 0.25,
                                          alpha = 0.05,
                                          min_samples = 20) {
  
  # validation
  validation <- validate_input_bulk(
    expression_data = expression_data,
    sex = sex,
    phenotype = phenotype,
    sex_labels_vector = sex_labels_vector,
    phenotype_labels_vector = phenotype_labels_vector,
    min_samples = min_samples
  )
  
  # factors
  phenotype <- factor(phenotype, levels = phenotype_labels_vector)
  sex <- factor(sex, levels = sex_labels_vector)
  
  # combined group
  group <- factor(paste(phenotype, sex, sep = "_"))
  
  # design matrix (USED EVERYWHERE)
  design <- model.matrix(~ 0 + group)
  colnames(design) <- levels(group)
  
  # voom flag
  used_voom <- FALSE
  fit <- NULL
  
  # check if raw counts
  is_likely_counts <- mean(expression_data %% 1 == 0, na.rm = TRUE) > 0.99
  
  if (is_likely_counts) {
    
    warning(
      "Expression data appear to be raw counts. Applying limma-voom."
    )
    
    v <- limma::voom(expression_data, design, plot = FALSE)
    
    # IMPORTANT: keep full voom object (E + weights)
    fit <- limma::lmFit(v, design)
    used_voom <- TRUE
    
  } else {
    
    # already normalized/log-expression
    fit <- limma::lmFit(expression_data, design)
  }
  
  # contrasts
  group_wt_f <- paste0(phenotype_labels_vector[1], "_", sex_labels_vector[1])
  group_tg_f <- paste0(phenotype_labels_vector[2], "_", sex_labels_vector[1])
  group_wt_m <- paste0(phenotype_labels_vector[1], "_", sex_labels_vector[2])
  group_tg_m <- paste0(phenotype_labels_vector[2], "_", sex_labels_vector[2])
  
  contrast_formula <- paste0(
    "(", group_tg_m, " - ", group_wt_m, ") - (",
    group_tg_f, " - ", group_wt_f, ")"
  )
  
  contrast_matrix <- limma::makeContrasts(
    contrasts = contrast_formula,
    levels = design
  )
  
  # fit model
  fit2 <- limma::contrasts.fit(fit, contrast_matrix)
  fit2 <- limma::eBayes(fit2)
  
  # results
  all_res <- limma::topTable(fit2, number = Inf, sort.by = "P")
  all_res$gene <- rownames(all_res)
  
  # prevent NOTE in R CMD check
  adj.P.Val <- logFC <- NULL
  
  # significant genes
  sig_res <- subset(all_res, adj.P.Val < alpha & abs(logFC) > min_logfc)
  
  return(list(
    all_results = all_res,
    sig_results = sig_res,
    summary_stats = data.frame(
      n_total_genes = nrow(all_res),
      n_sig_genes = nrow(sig_res),
      voom_used = used_voom,
      stringsAsFactors = FALSE
    ),
    validation = validation
  ))
}
