library(testthat)
library(DOtools)
library(Seurat)
library(SingleCellExperiment)

test_that("DO.MultiDGE returns merged dataframe with SC and PB results", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expect_true(all(c("gene", "celltype", "condition") %in% colnames(result)))
  expect_true(any(grepl("SC_wilcox", colnames(result))))
})

test_that("DO.MultiDGE works with SingleCellExperiment input", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expect_true(all(c("gene", "celltype", "condition") %in% colnames(result)))
})

test_that("DO.MultiDGE stops when ident_ctrl not found", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  expect_error(
    DO.MultiDGE(
      sce_object = sce_data,
      sample_col = "orig.ident",
      method_sc = "wilcox",
      annotation_col = "annotation",
      ident_ctrl = "nonexistent_condition"
    ),
    "was not found in meta data"
  )
})

test_that("DO.MultiDGE works with different method_sc", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  # Test with different methods
  methods_to_test <- c("wilcox", "t")

  for(method in methods_to_test) {
    result <- DO.MultiDGE(
      sce_object = sce_data,
      sample_col = "orig.ident",
      method_sc = method,
      annotation_col = "annotation",
      ident_ctrl = "healthy"
    )

    expect_true(any(grepl(paste0("SC_", method), colnames(result))))
  }
})

test_that("DO.MultiDGE handles min_pct and logfc_threshold parameters", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy",
    min_pct = 0.1,
    logfc_threshold = 0.25
  )

  expect_true(all(c("gene", "celltype", "condition") %in% colnames(result)))
})

test_that("DO.MultiDGE works with only_pos = TRUE", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy",
    only_pos = TRUE
  )

  expect_true(all(c("gene", "celltype", "condition") %in% colnames(result)))
})

test_that("DO.MultiDGE handles cell count filtering", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy",
    min_cells_group = 5
  )

  expect_s3_class(result, "data.frame")
})

test_that("DO.MultiDGE works with different assays", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  seurat_obj <- as.Seurat(sce_data)

  result <- DO.MultiDGE(
    sce_object = seurat_obj,
    assay = "RNA",
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expect_true(all(c("gene", "celltype", "condition") %in% colnames(result)))
})

test_that("DO.MultiDGE returns proper column structure", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expected_base_cols <- c("gene", "pct.1", "pct.2", "celltype", "condition")
  expect_true(all(expected_base_cols %in% colnames(result)))
  expect_true(any(grepl("SC_wilcox", colnames(result))))
})

test_that("DO.MultiDGE works with additional FindMarkers parameters", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy",
    min.cells.feature = 3,
    verbose = FALSE
  )

  expect_s3_class(result, "data.frame")
})

test_that("DO.MultiDGE handles different group_by columns", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  if ("condition" %in% colnames(sce_data@colData)) {
    result <- DO.MultiDGE(
      sce_object = sce_data,
      group_by = "condition",
      sample_col = "orig.ident",
      method_sc = "wilcox",
      annotation_col = "annotation",
      ident_ctrl = "healthy"
    )

    expect_s3_class(result, "data.frame")
  }
})


test_that("DO.MultiDGE handles the internal .suppressDeprecationWarnings", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expect_s3_class(result, "data.frame")
})

test_that("DO.MultiDGE handles the PB_ident creation and usage", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expect_s3_class(result, "data.frame")
})

test_that("DO.MultiDGE column renaming works correctly", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  sc_cols <- grep("SC_", colnames(result), value = TRUE)
  expect_true(length(sc_cols) > 0)
  expect_true(all(c("gene", "celltype", "condition") %in% colnames(result)))
})

test_that("DO.MultiDGE handles the left join operation correctly", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expect_s3_class(result, "data.frame")

  if (nrow(result) > 0) {
    expect_false(any(is.na(result$gene)))
    expect_false(any(is.na(result$celltype)))
    expect_false(any(is.na(result$condition)))
  }
})

test_that("DO.MultiDGE logging doesn't interfere with execution", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expect_s3_class(result, "data.frame")
})

test_that("DO.MultiDGE works with minimal parameters", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expect_s3_class(result, "data.frame")
})

test_that("DO.MultiDGE pseudo-bulk aggregation works", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expect_s3_class(result, "data.frame")
})

# TESTS FOR SPECIFIC FUNCTIONAL PATHS THAT ARE SAFE

test_that("DO.MultiDGE handles the AggregateExpression pathway", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  # This tests the pseudo-bulk creation without triggering empty results
  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",  # This is critical for aggregation
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  expect_s3_class(result, "data.frame")
})

test_that("DO.MultiDGE handles annotation name consistency check", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  # This tests the annotation name consistency logic
  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",  # Use standard annotation column
    ident_ctrl = "healthy"
  )

  expect_s3_class(result, "data.frame")
})

test_that("DO.MultiDGE handles the comparison loop structure", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  # Test with a control condition that exists
  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  # handle the comparison loops without error
  expect_s3_class(result, "data.frame")
})

test_that("DO.MultiDGE handles the cell count validation", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  # Test with reasonable min_cells_group
  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy",
    min_cells_group = 3  # Default value
  )

  expect_s3_class(result, "data.frame")
})

test_that("DO.MultiDGE handles the result collection and merging", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  # Test the final merged result structure
  expect_s3_class(result, "data.frame")
  if (nrow(result) > 0) {
    # key columns for the merge
    expect_true(all(c("gene", "celltype", "condition") %in% colnames(result)))
  }
})

# TEST FOR THE DESeq2 PSEUDO-BULK PATHWAY
test_that("DO.MultiDGE DESeq2 pseudo-bulk analysis completes", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",  # Required for pseudo-bulk
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  # should complete the DESeq2 pseudo-bulk pathway
  expect_s3_class(result, "data.frame")
})

# TEST FOR THE SINGLE-CELL ANALYSIS PATHWAY
test_that("DO.MultiDGE single-cell analysis completes", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  result <- DO.MultiDGE(
    sce_object = sce_data,
    sample_col = "orig.ident",
    method_sc = "wilcox",
    annotation_col = "annotation",
    ident_ctrl = "healthy"
  )

  # Should complete single-cell analysis pathway
  expect_s3_class(result, "data.frame")
  expect_true(any(grepl("SC_wilcox", colnames(result))))
})

# COMPREHENSIVE TEST COVERING MULTIPLE PARAMETERS
test_that("DO.MultiDGE comprehensive parameter test", {
  sce_data <- readRDS(system.file("extdata", "sce_data.rds", package = "DOtools"))

  # Test multiple parameter combinations that are known to work
  test_combinations <- list(
    list(method_sc = "wilcox", only_pos = FALSE),
    list(method_sc = "wilcox", only_pos = TRUE),
    list(method_sc = "t", only_pos = FALSE)
  )

  for (params in test_combinations) {
    result <- DO.MultiDGE(
      sce_object = sce_data,
      sample_col = "orig.ident",
      method_sc = params$method_sc,
      annotation_col = "annotation",
      ident_ctrl = "healthy",
      only_pos = params$only_pos
    )

    expect_s3_class(result, "data.frame")
    if (nrow(result) > 0) {
      expect_true(any(grepl(paste0("SC_", params$method_sc), colnames(result))))
    }
  }
})
