library(testthat)

test_that("binary roc_auc uses available probability columns", {
  skip_on_cran()
  required <- c("parsnip", "workflows", "recipes", "yardstick", "rsample")
  lapply(required, skip_if_not_installed)

  data(iris)
  df <- iris[iris$Species != "setosa", c("Sepal.Length", "Sepal.Width", "Species")]
  df$Species <- factor(df$Species)
  levels(df$Species) <- c("negative class", "positive class")

  fit <- fastml(
    data = df,
    label = "Species",
    algorithms = "logistic_reg",
    task = "classification",
    resampling_method = "none",
    use_default_tuning = FALSE,
    test_size = 0.3,
    seed = 123,
    bootstrap_ci = FALSE,
    event_class = "second"
  )

  perf <- fit$performance[[1]]
  if (is.list(perf) && !is.data.frame(perf)) {
    perf <- perf[[1]]
  }

  expect_true("roc_auc" %in% perf$.metric)
  roc_val <- perf$.estimate[perf$.metric == "roc_auc"][1]
  expect_true(is.finite(roc_val))

  preds <- fit$predictions[[1]]
  if (is.list(preds) && !is.data.frame(preds)) {
    preds <- preds[[1]]
  }
  expect_true(any(grepl("^\\.pred_", names(preds))))
})

test_that("binary probability column resolver handles sanitized names and explicit fallback", {
  res <- fastml:::fastml_resolve_binary_prob_column(
    prob_cols = c(".pred_pos.class", ".pred_neg.class"),
    truth_levels = c("pos class", "neg class"),
    event_class = "first"
  )
  expect_identical(res$prob_col, ".pred_pos.class")
  expect_false(isTRUE(res$used_fallback))

  res_fallback <- fastml:::fastml_resolve_binary_prob_column(
    prob_cols = c(".prob0", ".prob1"),
    truth_levels = c("no", "yes"),
    event_class = "second"
  )
  expect_null(res_fallback$prob_col)
  expect_false(isTRUE(res_fallback$used_fallback))

  res_fallback_allowed <- fastml:::fastml_resolve_binary_prob_column(
    prob_cols = c(".prob0", ".prob1"),
    truth_levels = c("no", "yes"),
    event_class = "second",
    allow_fallback = TRUE
  )
  expect_identical(res_fallback_allowed$prob_col, ".prob1")
  expect_true(isTRUE(res_fallback_allowed$used_fallback))
})

test_that("configured roc_auc accepts explicit estimator", {
  required <- c("yardstick")
  lapply(required, skip_if_not_installed)

  data(iris)
  df <- iris[iris$Species != "setosa", ]
  df$Species <- factor(df$Species)

  set.seed(123)
  df$.pred_versicolor <- runif(nrow(df))

  roc_fun <- fastml:::fastml_configured_roc_auc("macro")

  expect_silent(
    roc_fun(df, truth = Species, .pred_versicolor, estimator = "binary")
  )
})

test_that("logloss and brier_score are computed when probabilities are available", {
  skip_on_cran()
  required <- c("parsnip", "workflows", "recipes", "yardstick", "rsample")
  lapply(required, skip_if_not_installed)

  data(iris)
  df <- iris[iris$Species != "setosa", c("Sepal.Length", "Sepal.Width", "Species")]
  df$Species <- factor(df$Species)
  levels(df$Species) <- c("negative class", "positive class")

  fit <- fastml(
    data = df,
    label = "Species",
    algorithms = "logistic_reg",
    task = "classification",
    resampling_method = "none",
    use_default_tuning = FALSE,
    test_size = 0.3,
    seed = 321,
    bootstrap_ci = FALSE,
    metric = "logloss",
    event_class = "second"
  )

  perf <- fit$performance[[1]]
  if (is.list(perf) && !is.data.frame(perf)) {
    perf <- perf[[1]]
  }

  expect_true(all(c("logloss", "brier_score", "ece") %in% perf$.metric))
  calib_vals <- perf$.estimate[perf$.metric %in% c("logloss", "brier_score", "ece")]
  expect_true(all(is.finite(calib_vals)))
  expect_true(all(calib_vals >= 0))
})
