test_that("Test Genetic Interaction score calculations", {
  skip_if_figshare_unavailable()
  skip_if_depmap_changed()
  data_dir <- test_example_data_dir()

  gimap_dataset <- get_example_data("gimap", data_dir = data_dir) %>%
    gimap_filter() %>%
    gimap_annotate(cell_line = "HELA") %>%
    gimap_normalize(
      timepoints = "day",
      missing_ids_file = tempfile()
    ) %>%
    calc_gi()

  # Test that all expected data structures exist and are correct type
  testthat::expect_s3_class(gimap_dataset$linear_model, "lm")
  testthat::expect_true(is.data.frame(gimap_dataset$gi_scores))
  testthat::expect_true(nrow(gimap_dataset$gi_scores) > 0)

  # Test that required columns exist
  expected_cols <- c("mean_expected_cs", "mean_observed_cs", "gi_score", "p_val", "fdr", "pgRNA_target", "target_type")
  testthat::expect_true(all(expected_cols %in% colnames(gimap_dataset$gi_scores)))

  # Test that values are reasonable (not NA, not infinite)
  testthat::expect_false(any(is.na(gimap_dataset$gi_scores$mean_expected_cs)))
  testthat::expect_false(any(is.na(gimap_dataset$gi_scores$mean_observed_cs)))
  testthat::expect_false(any(is.na(gimap_dataset$gi_scores$gi_score)))
  testthat::expect_false(any(is.infinite(gimap_dataset$gi_scores$gi_score)))

  # Test that we have the expected target types
  expected_target_types <- c("gene_gene", "gene_ctrl", "ctrl_gene")
  testthat::expect_true(all(gimap_dataset$gi_scores$target_type %in% expected_target_types))

  # Test that linear model has reasonable coefficients (not NA or infinite)
  testthat::expect_false(any(is.na(gimap_dataset$linear_model$coefficients)))
  testthat::expect_false(any(is.infinite(gimap_dataset$linear_model$coefficients)))

  # Test that we have both single and double targeting results
  testthat::expect_true("gene_gene" %in% gimap_dataset$gi_scores$target_type)
  testthat::expect_true(any(c("gene_ctrl", "ctrl_gene") %in% gimap_dataset$gi_scores$target_type))
})


test_that("Test Genetic Interaction score calculations using LFC", {
  skip_if_figshare_unavailable()
  skip_if_depmap_changed()
  data_dir <- test_example_data_dir()

  gimap_dataset <- get_example_data("gimap", data_dir = data_dir) %>%
    gimap_filter() %>%
    gimap_annotate(cell_line = "HELA") %>%
    gimap_normalize(
      timepoints = "day",
      adj_method = "no_adjustment",
      missing_ids_file = tempfile()
    ) %>%
    calc_gi(use_lfc = TRUE)

  testthat::expect_true(class(gimap_dataset)[1] == "list")
})


test_that("Test Genetic Interaction score without normalization", {
  skip_if_figshare_unavailable()
  skip_if_depmap_changed()
  data_dir <- test_example_data_dir()

  gimap_dataset_wo <- get_example_data("gimap", data_dir = data_dir) %>%
    gimap_filter() %>%
    gimap_annotate(cell_line = "HELA") %>%
    gimap_normalize(
      normalize_by_unexpressed = FALSE,
      timepoints = "day",
      missing_ids_file = tempfile()
    ) %>%
    calc_gi()

  gimap_dataset_w <- get_example_data("gimap", data_dir = data_dir) %>%
    gimap_filter() %>%
    gimap_annotate(cell_line = "HELA") %>%
    gimap_normalize(
      normalize_by_unexpressed = TRUE,
      timepoints = "day",
      missing_ids_file = tempfile()
    ) %>%
    calc_gi()


  # Are the GI scores the same? No
  testthat::expect_false(
    all(gimap_dataset_wo$gi_scores$gi_score == gimap_dataset_w$gi_scores$gi_score)
  )

  # Are the log fold change values the same? No
  testthat::expect_false(
    all(gimap_dataset_wo$normalized_log_fc$lfc == gimap_dataset_w$normalized_log_fc$lfc)
  )

  # Are the CRISPR scores the same? No
  testthat::expect_false(
    all(gimap_dataset_wo$normalized_log_fc$crispr_score == gimap_dataset_w$normalized_log_fc$crispr_score)
  )

  table(
    gimap_dataset_w$normalized_log_fc$unexpressed_ctrl_flag,
    gimap_dataset_w$normalized_log_fc$norm_ctrl_flag
  )
})

test_that("Test Genetic Interaction score calculations without ctrl_ctrl controls", {
  skip_if_figshare_unavailable()
  skip_if_depmap_changed()
  data_dir <- test_example_data_dir()

  # Get the example data and modify it to remove ctrl_ctrl controls
  gimap_dataset <- get_example_data("gimap", data_dir = data_dir) %>%
    gimap_filter() %>%
    gimap_annotate(cell_line = "HELA")

  # Remove ctrl_ctrl controls from the annotation to simulate Ito et al. dataset
  gimap_dataset$annotation <- gimap_dataset$annotation %>%
    dplyr::filter(target_type != "ctrl_ctrl")

  # This should work without error when using no_adjustment and use_lfc = TRUE
  gimap_dataset_no_ctrl <- gimap_dataset %>%
    gimap_normalize(
      timepoints = "day",
      adj_method = "no_adjustment",
      missing_ids_file = tempfile()
    ) %>%
    calc_gi(use_lfc = TRUE)

  # Check that the function completed successfully
  testthat::expect_true(class(gimap_dataset_no_ctrl)[1] == "list")
  testthat::expect_false(is.null(gimap_dataset_no_ctrl$gi_scores))
  testthat::expect_false(is.null(gimap_dataset_no_ctrl$linear_model))

  # Check that we have GI scores calculated
  testthat::expect_true(nrow(gimap_dataset_no_ctrl$gi_scores) > 0)

  # Check that the linear model was created successfully
  testthat::expect_true(class(gimap_dataset_no_ctrl$linear_model)[1] == "lm")

  # Check that mean_expected_lfc values are not all NA
  testthat::expect_false(all(is.na(gimap_dataset_no_ctrl$gi_scores$mean_expected_lfc)))

  # Check that gi_score values are not all NA
  testthat::expect_false(all(is.na(gimap_dataset_no_ctrl$gi_scores$gi_score)))

  # Verify that no ctrl_ctrl controls exist in the final results
  testthat::expect_false("ctrl_ctrl" %in% gimap_dataset_no_ctrl$gi_scores$target_type)

  # Check that the LFC data structure exists (since use_lfc = TRUE)
  testthat::expect_false(is.null(gimap_dataset_no_ctrl$lfc))
  testthat::expect_true("single_lfc" %in% names(gimap_dataset_no_ctrl$lfc))
  testthat::expect_true("double_lfc" %in% names(gimap_dataset_no_ctrl$lfc))

  # This should work without error when using use_ntc = TRUE
  gimap_dataset_no_ntc <- get_example_data("gimap", data_dir = data_dir) %>%
    gimap_filter() %>%
    gimap_annotate(cell_line = "HELA") %>%
    gimap_normalize(
      normalize_by_unexpressed = FALSE,
      timepoints = "day",
      missing_ids_file = tempfile()
    ) %>%
    calc_gi(use_ntc = FALSE)

  plot_exp_v_obs_scatter(gimap_dataset_no_ntc)
  plot_exp_v_obs_scatter(gimap_dataset_no_ctrl)

  plot_rank_scatter(gimap_dataset_no_ntc)
  plot_rank_scatter(gimap_dataset_no_ctrl)

  plot_volcano(gimap_dataset_no_ntc)
  plot_volcano(gimap_dataset_no_ctrl)

  # Check that gi_score values are not all NA
  testthat::expect_false(all(is.na(gimap_dataset_no_ctrl$gi_scores$gi_score)))

  # Verify that no ctrl_ctrl controls exist in the final results
  testthat::expect_false("ctrl_ctrl" %in% gimap_dataset_no_ctrl$gi_scores$target_type)
})

test_that("Test proper error messages for incompatible settings", {
  skip_if_figshare_unavailable()
  skip_if_depmap_changed()
  data_dir <- test_example_data_dir()

  # Get the example data and modify it to remove ctrl_ctrl controls
  gimap_dataset <- get_example_data("gimap", data_dir = data_dir) %>%
    gimap_filter() %>%
    gimap_annotate(cell_line = "HELA")

  # Remove ctrl_ctrl controls from the annotation
  gimap_dataset$annotation <- gimap_dataset$annotation %>%
    dplyr::filter(target_type != "ctrl_ctrl")

  # This should fail during normalization when trying to use negative_control_adj without ctrl_ctrl
  # This is expected behavior - user should use "no_adjustment" when no ctrl_ctrl available
  testthat::expect_error(
    gimap_dataset %>%
      gimap_normalize(
        timepoints = "day",
        adj_method = "negative_control_adj",
        missing_ids_file = tempfile()
      ),
    "negative_control.*doesn't exist"
  )

  # This should fail when trying to use CRISPR scores without proper normalization
  # User should set use_lfc = TRUE when using no_adjustment
  testthat::expect_error(
    gimap_dataset %>%
      gimap_normalize(
        timepoints = "day",
        adj_method = "no_adjustment",
        missing_ids_file = tempfile()
      ) %>%
      calc_gi(use_lfc = FALSE),
    "No CRISPR scores found"
  )
})
