test_that("survdnn() fits a model and returns correct structure", {
  skip_on_cran()
  skip_if_not(torch::torch_is_installed())

  set.seed(123)
  n <- 100
  df <- data.frame(
    time   = rexp(n, rate = 0.1),
    status = rbinom(n, 1, 0.7),
    x1     = rnorm(n),
    x2     = rbinom(n, 1, 0.5)
  )

  mod <- survdnn(
    Surv(time, status) ~ x1 + x2,
    data = df,
    hidden = c(8, 4),
    activation = "relu",
    epochs = 10,
    lr = 1e-3,
    loss = "cox",
    verbose = FALSE
  )

  expect_s3_class(mod, "survdnn")
  expect_true(inherits(mod$model, "nn_module"))
  expect_equal(deparse(mod$formula), deparse(Surv(time, status) ~ x1 + x2))
  expect_type(mod$final_loss, "double")
  expect_length(mod$loss_history, 10)

  expect_named(
    mod,
    c(
      "activation",
      "aft_loc",
      "aft_log_sigma",
      "batch_norm",
      "coxtime_time_center",
      "coxtime_time_scale",
      "data",
      "device",
      "dropout",
      "epochs",
      "final_loss",
      "formula",
      "hidden",
      "loss",
      "loss_history",
      "lr",
      "model",
      "na_action",
      "optim_args",
      "optimizer",
      "threads",
      "x_center",
      "x_scale",
      "xnames"
    ),
    ignore.order = TRUE
  )

  # sanity: for loss="cox", AFT/CoxTime metadata should be NA
  expect_true(is.na(mod$aft_log_sigma))
  expect_true(is.na(mod$aft_loc))
  expect_true(is.na(mod$coxtime_time_center))
  expect_true(is.na(mod$coxtime_time_scale))
})

test_that("survdnn() validates .threads", {
  skip_on_cran()
  skip_if_not(torch::torch_is_installed())

  set.seed(123)
  df <- data.frame(
    time   = rexp(20, rate = 0.1),
    status = rbinom(20, 1, 0.7),
    x1     = rnorm(20)
  )

  expect_error(
    survdnn(
      Surv(time, status) ~ x1,
      data = df,
      epochs = 1,
      verbose = FALSE,
      .threads = 0
    ),
    "`.threads` must be a single positive integer or NULL."
  )
})


test_that("survdnn() is reproducible given .seed", {
  skip_on_cran()
  skip_if_not_installed("torch")
  skip_if_not(torch::torch_is_installed())

  set.seed(123)
  n <- 80
  df <- data.frame(
    time   = rexp(n, rate = 0.1),
    status = rbinom(n, 1, 0.7),
    x1     = rnorm(n),
    x2     = rbinom(n, 1, 0.5)
  )

  mod1 <- survdnn(
    Surv(time, status) ~ x1 + x2,
    data   = df,
    hidden = c(8),
    activation = "relu",
    lr     = 1e-3,
    epochs = 10,
    loss   = "cox",
    verbose = FALSE,
    .seed   = 999
  )

  mod2 <- survdnn(
    Surv(time, status) ~ x1 + x2,
    data   = df,
    hidden = c(8),
    activation = "relu",
    lr     = 1e-3,
    epochs = 10,
    loss   = "cox",
    verbose = FALSE,
    .seed   = 999
  )

  expect_equal(mod1$loss_history, mod2$loss_history)
})
