# Suppress cli output during testing
options(cli.default_handler = function(...) {})

load(metacore::metacore_example("pilot_ADaM.rda"))
spec <- metacore %>% select_dataset("ADSL", verbose = "silent")
test_that("drop_unspec_vars", {
  data <- haven::read_xpt(metatools_example("adsl.xpt")) %>%
    mutate(AGEGR2 = "DUMMY", AGEGR2N = 99, foo = "Hello", foo2 = "world")

  man_vars <- metacore$ds_vars %>%
    filter(dataset == "ADSL") %>%
    pull(variable)
  man_dat <- data %>%
    select(all_of(man_vars))
  drop_unspec_vars(data, spec) %>%
    expect_equal(man_dat)
  expect_message(drop_unspec_vars(data, spec),
    label = "The following variable(s) were dropped:\n  foo\n  foo2"
  )
})


test_that("build_from_derived", {
  ds_list <- list(DM = haven::read_xpt(metatools_example("dm.xpt")))

  expect_error(build_from_derived(spec, ds_list, keep = FALSE))
  # Vars that should be brought through
  man_vars <- spec$derivations %>%
    filter(str_detect(derivation, "^DM\\.")) %>%
    pull(derivation) %>%
    str_remove("^DM\\.") %>%
    unique() %>%
    c("TRT01P") %>%
    sort()
  build_from_derived(spec, ds_list,
    predecessor_only = FALSE,
    keep = FALSE
  ) %>%
    names() %>%
    sort() %>%
    expect_equal(man_vars)

  # Vars pulled through with old columns kept
  man_vars <- spec$derivations %>%
    filter(str_detect(derivation, "^DM\\.")) %>%
    pull(derivation) %>%
    str_remove("^DM\\.") %>%
    unique() %>%
    c(., "TRT01P") %>%
    sort()

  expect_warning(
    build_from_derived(spec, ds_list,
      predecessor_only = FALSE,
      keep = TRUE
    ) %>%
      names() %>%
      sort() %>%
      expect_equal(man_vars),
    label = paste0(
      "Setting 'keep' = TRUE has been superseded, and will be",
      " unavailable in future releases. Please consider setting",
      " 'keep' equal to 'ALL' or 'PREREQUISITE'."
    )
  )

  # Pulling through from more than one dataset
  spec2 <- metacore %>% select_dataset("ADAE", verbose = "silent")
  adae_auto <- build_from_derived(spec2,
    ds_list = list(
      "AE" = safetyData::sdtm_ae,
      "ADSL" = safetyData::adam_adsl
    ),
    predecessor_only = FALSE,
    keep = FALSE
  )
  ae_part_vars <- spec2$derivations %>%
    filter(str_detect(derivation, "AE\\.[[:alnum:]]*$")) %>%
    pull(derivation) %>%
    str_remove("^AE\\.") %>%
    c("STUDYID", "USUBJID", .)

  ae_part <- select(safetyData::sdtm_ae, all_of(ae_part_vars))

  adsl_part_vars <- spec2$derivations %>%
    filter(str_detect(derivation, "ADSL\\.[[:alnum:]]*$")) %>%
    pull(derivation) %>%
    str_remove("^ADSL\\.")
  adsl_part <-
    select(safetyData::adam_adsl, all_of(adsl_part_vars)) |>
    rename(TRTA = TRT01A, TRTAN = TRT01AN)

  adae_man <- full_join(adsl_part, ae_part, by = c("STUDYID", "USUBJID"), multiple = "all") %>%
    select(all_of(names(adae_auto)), everything())
  expect_equal(adae_auto, adae_man)


  # Pulling through from one dataset when spec has more than one
  adae_auto_adsl_only <- build_from_derived(spec2,
    ds_list = list("ADSL" = safetyData::adam_adsl),
    predecessor_only = FALSE,
    keep = FALSE
  ) |>
    order_cols(spec2)
  adsl_man <- order_cols(adsl_part, spec2)
  expect_equal(adae_auto_adsl_only, adsl_man)

  adsl <- safetyData::adam_adsl
  ae <- safetyData::sdtm_ae
  adae_auto_unnamed <- build_from_derived(spec2,
    ds_list = list(ae, adsl),
    predecessor_only = FALSE,
    keep = FALSE
  )
  expect_equal(adae_auto, adae_man)

  expect_warning(build_from_derived(spec2,
    ds_list = list(safetyData::sdtm_ae, adsl),
    predecessor_only = FALSE,
    keep = FALSE
  ))

  # Pulling through all columns from original dataset
  adae_full <- build_from_derived(spec2,
    ds_list = list(
      "AE" = safetyData::sdtm_ae,
      "ADSL" = safetyData::adam_adsl
    ),
    predecessor_only = FALSE,
    keep = "ALL"
  )

  full_adsl_part <- safetyData::adam_adsl %>%
    mutate(TRTA = TRT01A, TRTAN = TRT01AN)

  adae_all_man <- full_join(full_adsl_part, safetyData::sdtm_ae, by = c("STUDYID", "USUBJID"), multiple = "all")

  expect_equal(adae_full, adae_all_man)

  # Pulling through columns required for future derivations
  spec3 <- metacore %>% select_dataset("ADAE", verbose = "silent")

  adae_prereq <- build_from_derived(spec3,
    ds_list = list(
      "AE" = safetyData::sdtm_ae,
      "ADSL" = safetyData::adam_adsl
    ),
    predecessor_only = FALSE,
    keep = "PREREQUISITE"
  )

  adae_auto <- build_from_derived(spec3,
    ds_list = list(
      "AE" = safetyData::sdtm_ae,
      "ADSL" = safetyData::adam_adsl
    ),
    predecessor_only = FALSE,
    keep = "PREREQUISITE"
  )


  adae_all <- build_from_derived(spec3,
    ds_list = list(
      "AE" = safetyData::sdtm_ae,
      "ADSL" = safetyData::adam_adsl
    ),
    predecessor_only = FALSE,
    keep = "ALL"
  )

  adae_prereq_man <- adae_all %>%
    select(c(names(adae_auto)))

  expect_equal(adae_prereq, adae_prereq_man)
})


test_that("add_variables add missing variables to the metacore object", {
  load(metacore::metacore_example("pilot_ADaM.rda"))
  spec <- metacore %>% select_dataset("ADSL", verbose = "silent")
  data <- haven::read_xpt(metatools_example("adsl.xpt")) %>%
    mutate(AGEGR2 = "DUMMY", AGEGR2N = 99)
  data_mis <- data %>%
    select(-TRTSDT, -TRT01P, -TRT01PN)
  # Check data when there is missing
  fx_miss <- add_variables(data_mis, spec) %>%
    select(TRTSDT, TRT01P, TRT01PN)
  man_miss <- data %>%
    mutate(
      TRTSDT = as.Date(NA_integer_),
      TRT01P = NA_character_,
      TRT01PN = NA_integer_
    ) %>%
    select(TRTSDT, TRT01P, TRT01PN)
  expect_equal(fx_miss, man_miss)
  # Check data when there isn't any missing
  expect_equal(
    add_variables(data, spec),
    data
  )
})

test_that("drop_unspec_vars verbose parameter", {
  data <- haven::read_xpt(metatools_example("adsl.xpt")) %>%
    mutate(foo = "Hello", foo2 = "world")

  man_vars <- metacore$ds_vars %>%
    filter(dataset == "ADSL") %>%
    pull(variable)
  man_dat <- data %>%
    select(all_of(man_vars))

  # Test verbose = "message" (default behavior)
  expect_message(
    drop_unspec_vars(data, spec, verbose = "message"),
    "The following variable\\(s\\) were dropped:"
  )

  # Test verbose = "warn" (suppress messages)
  expect_silent(
    drop_unspec_vars(data, spec, verbose = "warn")
  )

  # Test verbose = "silent" (suppress all output)
  expect_silent(
    drop_unspec_vars(data, spec, verbose = "silent")
  )

  # Verify all verbose levels return same result
  result_message <- drop_unspec_vars(data, spec, verbose = "message")
  result_warn <- drop_unspec_vars(data, spec, verbose = "warn")
  result_silent <- drop_unspec_vars(data, spec, verbose = "silent")

  expect_equal(result_message, man_dat)
  expect_equal(result_warn, man_dat)
  expect_equal(result_silent, man_dat)

  # Test invalid verbose value
  expect_error(
    drop_unspec_vars(data, spec, verbose = "invalid"),
    "should be one of: message, warn, silent"
  )
})

test_that("build_from_derived verbose controls prepare_join messages", {
  load(metacore::metacore_example("pilot_ADaM.rda"))
  spec2 <- metacore %>% select_dataset("ADAE", verbose = "silent")

  # Use safetyData datasets and add a conflicting non-key column
  # STUDYID is a key column, so add a different column that will conflict
  ae <- safetyData::sdtm_ae %>%
    mutate(TESTCOL = "AE_VALUE") # Add a non-key column

  adsl <- safetyData::adam_adsl %>%
    mutate(TESTCOL = "ADSL_VALUE") # Same column with different value

  ds_list <- list(AE = ae, ADSL = adsl)

  # Test that conflicting column messages are shown with verbose = "message"
  expect_message(
    build_from_derived(spec2, ds_list, predecessor_only = FALSE, verbose = "message", keep = "ALL"),
    "Dropping column\\(s\\) from"
  )

  # Test that messages are suppressed with verbose = "warn" and "silent"
  expect_silent(
    build_from_derived(spec2, ds_list, predecessor_only = FALSE, verbose = "warn", keep = "ALL")
  )

  expect_silent(
    build_from_derived(spec2, ds_list, predecessor_only = FALSE, verbose = "silent", keep = "ALL")
  )
})
