make_linear_data <- function(n = 200, p = 30, k_true = 5, seed = 1) {
  set.seed(seed)
  beta <- c(c(3, 2, 1.5, 1, 0.5)[seq_len(k_true)], rep(0, p - k_true))
  x <- matrix(rnorm(n * p), n, p)
  y <- as.numeric(x %*% beta + rnorm(n) * 0.5)
  list(x = x, y = y, beta = beta, n = n, p = p)
}

test_that("gaussian FW recovers the active features at k = k_true", {
  d <- make_linear_data()
  fit <- combss(d$x, d$y, family = "gaussian", q = 10, verbose = FALSE)
  expect_s3_class(fit, "combss")
  expect_length(fit$subset_list, 10)
  expect_setequal(fit$subset_list[[5]], 1:5)
})

test_that("'linear' is an alias for 'gaussian'", {
  d <- make_linear_data()
  f1 <- combss(d$x, d$y, family = "gaussian", q = 5, verbose = FALSE)
  f2 <- combss(d$x, d$y, family = "linear",   q = 5, verbose = FALSE)
  expect_identical(f1$subset_list, f2$subset_list)
  expect_equal(f1$family, "gaussian")
  expect_equal(f2$family, "gaussian")
})

test_that("validation data selects the best k and stores the metric", {
  d <- make_linear_data()
  itr <- 1:140; iva <- 141:200
  fit <- combss(d$x[itr, ], d$y[itr],
                x_val = d$x[iva, ], y_val = d$y[iva],
                family = "gaussian", q = 10, verbose = FALSE)
  expect_false(is.null(fit$subset))
  expect_false(is.null(fit$mse))
  expect_length(fit$mse_path, 10)
  expect_equal(which.min(fit$mse_path), fit$best_k)
})

test_that("binomial FW separates labels in a clean simulation", {
  d <- make_linear_data()
  ybin <- as.numeric(plogis(d$x %*% d$beta) > 0.5)
  fit <- combss(d$x, ybin, family = "binomial", q = 8, verbose = FALSE)
  expect_s3_class(fit, "combss")
  expect_setequal(intersect(fit$subset_list[[5]], 1:5), 1:5)
})

test_that("multinomial FW recovers active features", {
  d <- make_linear_data()
  ymulti <- cut(as.numeric(d$x %*% d$beta),
                breaks = c(-Inf, -1, 1, Inf),
                labels = c("a", "b", "c"))
  fit <- combss(d$x, ymulti, family = "multinomial", q = 8, verbose = FALSE)
  expect_s3_class(fit, "combss")
  expect_true(length(fit$subset_list[[8]]) == 8)
})

test_that("coef() returns the chosen subset", {
  d <- make_linear_data()
  fit <- combss(d$x, d$y, family = "gaussian", q = 5, verbose = FALSE)
  expect_setequal(coef(fit, k = 3), 1:3)
})

test_that("invalid family is rejected", {
  d <- make_linear_data()
  expect_error(combss(d$x, d$y, family = "poisson", q = 3),
               "must be one of")
})
