test_that("fm_depth returns correct length and range (Tukey)", {
  set.seed(1)
  X <- matrix(rnorm(50 * 100), nrow = 50)
  d <- fm_depth(X, type = "tukey")
  expect_length(d, 50)
  expect_true(all(d >= 0))
  expect_true(all(d <= 1))
})

test_that("fm_depth returns correct range for simplicial variant", {
  set.seed(2)
  X <- matrix(rnorm(40 * 80), nrow = 40)
  d <- fm_depth(X, type = "simplicial")
  expect_length(d, 40)
  expect_true(all(d >= 0.5 - 1e-9))
  expect_true(all(d <= 1 + 1e-9))
})

test_that("fm_depth errors on non-matrix input", {
  expect_error(fm_depth(1:10), "'X' must be a numeric matrix")
})

test_that("fm_depth errors on mismatched grid", {
  X <- matrix(rnorm(20 * 50), nrow = 20)
  expect_error(fm_depth(X, grid = seq(0, 1, length.out = 40)),
               "'grid' must have the same length")
})

test_that("reference_curve returns a vector of correct length", {
  set.seed(3)
  X <- matrix(rnorm(30 * 60), nrow = 30)
  ref <- reference_curve(X)
  expect_length(ref, 60)
})

test_that("signed_distance_integral has correct sign structure", {
  M <- 60
  t <- seq(0, 1, length.out = M)
  X_above <- matrix(rep( 1, M), nrow = 1)
  X_below <- matrix(rep(-1, M), nrow = 1)
  X_zero  <- matrix(rep( 0, M), nrow = 1)
  X   <- rbind(X_above, X_below, X_zero)
  sdi <- signed_distance_integral(X, x_ref = X_zero[1, ], grid = t)
  expect_gt(sdi[1],  0)
  expect_lt(sdi[2],  0)
  expect_equal(sdi[3], 0, tolerance = 1e-10)
})

test_that("signed_depth returns fd_signed_depth object", {
  set.seed(7)
  X <- matrix(rnorm(50 * 80), nrow = 50)
  sd_obj <- signed_depth(X)
  expect_s3_class(sd_obj, "fd_signed_depth")
  expect_length(sd_obj$sdp, 50)
  expect_length(sd_obj$x_ref, 80)
})

test_that("krnn_fit returns predicted labels of correct length", {
  dat <- simulate_fd(n0 = 30, n1 = 30, M = 60, seed = 42)
  fit <- krnn_fit(dat$X[1:40, ], dat$y[1:40], dat$X[41:60, ], k = 5)
  expect_length(fit$predicted, 20)
  expect_true(all(fit$predicted %in% c(0L, 1L)))
})

test_that("krnn_cv selects a valid k", {
  dat <- simulate_fd(n0 = 30, n1 = 30, M = 60, seed = 1)
  cv  <- krnn_cv(dat$X, dat$y, k_max = 10, R = 3, seed = 1)
  expect_s3_class(cv, "krnn_cv")
  expect_true(cv$k_opt >= 1L && cv$k_opt <= 10L)
  expect_length(cv$cv_error, 10)
})

test_that("plot_krnn_cv runs without error", {
  dat <- simulate_fd(n0 = 30, n1 = 30, M = 60, seed = 1)
  cv  <- krnn_cv(dat$X, dat$y, k_max = 5, R = 3, seed = 1)
  expect_invisible(plot_krnn_cv(cv))
})

test_that("krnn_smoother returns krnn_smoother object", {
  dat <- simulate_fd(n0 = 30, n1 = 30, M = 60, seed = 5)
  sm  <- krnn_smoother(dat$X, dat$y, k = 5)
  expect_s3_class(sm, "krnn_smoother")
  expect_length(sm$prob, length(sm$sdp_eval))
})

test_that("plot_krnn_smoother runs without error", {
  dat <- simulate_fd(n0 = 30, n1 = 30, M = 60, seed = 5)
  sm  <- krnn_smoother(dat$X, dat$y, k = 5)
  expect_invisible(plot_krnn_smoother(sm))
})

test_that("bayes_depth_classify produces valid probabilities", {
  dat <- simulate_fd(n0 = 40, n1 = 40, M = 60, seed = 2)
  fit <- bayes_depth_classify(dat$X[1:60, ], dat$y[1:60], dat$X[61:80, ])
  expect_true(all(fit$prob >= 0 & fit$prob <= 1 + 1e-9))
  expect_true(all(abs(rowSums(fit$prob) - 1) < 1e-9))
})

test_that("logistic_depth_classify: model sdp runs without error", {
  dat <- simulate_fd(n0 = 40, n1 = 40, M = 60, seed = 3)
  fit <- logistic_depth_classify(dat$X[1:60, ], dat$y[1:60],
                                 dat$X[61:80, ], model = "sdp")
  expect_true(all(fit$predicted %in% c(0L, 1L)))
})

test_that("gam_depth_classify returns valid predictions", {
  dat <- simulate_fd(n0 = 40, n1 = 40, M = 60, seed = 4)
  fit <- gam_depth_classify(dat$X[1:60, ], dat$y[1:60], dat$X[61:80, ])
  expect_true(all(fit$predicted %in% c(0L, 1L)))
  expect_s3_class(fit, "fd_gam_fit")
})

test_that("simulate_fd dimensions are correct", {
  dat <- simulate_fd(n0 = 20, n1 = 30, M = 50, seed = 99)
  expect_equal(nrow(dat$X), 50)
  expect_equal(ncol(dat$X), 50)
  expect_equal(sum(dat$y == 0), 20)
  expect_equal(sum(dat$y == 1), 30)
})
