# ─────────────────────────────────────────────────────────────────────────────
# test-set-priors.R — tests for prior(), set_priors(), format(), print(),
#                     and get_default_priors()
# ─────────────────────────────────────────────────────────────────────────────

# ═════════════════════════════════════════════════════════════════════════════
# §1 — prior() construction
# ═════════════════════════════════════════════════════════════════════════════

test_that("prior('normal') returns a bvarnet_prior object", {
  p <- prior("normal", 0, 1)
  expect_s3_class(p, "bvarnet_prior")
})

test_that("prior('normal') has correct family_int", {
  expect_equal(prior("normal", 0, 1)$family_int, 1L)
})

test_that("prior('student_t') has correct family_int and preserves df", {
  p <- prior("student_t", 0, 1, df = 7)
  expect_equal(p$family_int, 2L)
  expect_equal(p$df, 7)
})

test_that("prior('cauchy') has correct family_int", {
  expect_equal(prior("cauchy", 0, 1)$family_int, 3L)
})

test_that("all Phase-1 families produce objects with expected family_int values", {
  supported <- list(
    list("normal",    1L),
    list("student_t", 2L),
    list("cauchy",    3L)
  )
  for (s in supported) {
    p <- prior(s[[1]], 0, 1)
    expect_equal(p$family_int, s[[2]], info = s[[1]])
  }
})

test_that("prior() built directly by user has is_default == FALSE", {
  expect_false(prior("normal", 0, 1)$is_default)
})

test_that("prior() stores loc and scale correctly", {
  p <- prior("normal", loc = 0.5, scale = 2)
  expect_equal(p$loc,   0.5)
  expect_equal(p$scale, 2)
})

test_that("unrecognised family stops with informative error", {
  expect_error(prior("horseshoe"), "Unrecognised prior family")
  expect_error(prior("flat"),      "Unrecognised prior family")
  expect_error(prior("laplace"),   "Unrecognised prior family")
})

test_that("scale <= 0 stops", {
  expect_error(prior("normal", 0, 0),  "scale")
  expect_error(prior("normal", 0, -1), "scale")
})

test_that("df <= 0 for student_t stops", {
  expect_error(prior("student_t", 0, 1, df = 0),  "df")
  expect_error(prior("student_t", 0, 1, df = -1), "df")
})

test_that("very large scale produces a warning", {
  expect_warning(prior("normal", 0, 100), "very large")
})

test_that("very small scale produces a warning", {
  expect_warning(prior("normal", 0, 0.001), "strongly informative")
})

test_that("non-student_t family ignores df (sets it to 0)", {
  expect_equal(prior("normal", 0, 1)$df, 0)
  expect_equal(prior("cauchy", 0, 1)$df, 0)
})


# ═════════════════════════════════════════════════════════════════════════════
# §2 — set_priors() defaults
# ═════════════════════════════════════════════════════════════════════════════

test_that("set_priors() returns a bvarnet_priors object", {
  expect_s3_class(set_priors(), "bvarnet_priors")
})

test_that("set_priors() has the correct names", {
  expect_named(set_priors(), c("intercept", "beta", "phi", "sd_u", "kappa", "sigma"))
})

test_that("default beta is Normal(0, 1)", {
  sp <- set_priors()
  expect_equal(sp$beta$family_int, 1L)
  expect_equal(sp$beta$loc,   0)
  expect_equal(sp$beta$scale, 1)
})

test_that("default phi scale is 0.5", {
  expect_equal(set_priors()$phi$scale, 0.5)
})

test_that("default sd_u scale is 1", {
  expect_equal(set_priors()$sd_u$scale, 1)
})

test_that("default sigma scale is 2.5", {
  expect_equal(set_priors()$sigma$scale, 2.5)
})

test_that("default kappa scale is 2", {
  expect_equal(set_priors()$kappa$scale, 2)
})

test_that("all defaults have is_default == TRUE", {
  sp <- set_priors()
  for (nm in names(sp)) {
    expect_true(sp[[nm]]$is_default, info = nm)
  }
})

test_that("overriding beta sets is_default to FALSE for beta only", {
  sp <- set_priors(beta = prior("cauchy", 0, 0.5))
  expect_equal(sp$beta$family_int, 3L)
  expect_false(sp$beta$is_default)
  # Other slots unchanged
  expect_true(sp$phi$is_default)
  expect_true(sp$sd_u$is_default)
})

test_that("overriding phi does not affect other slots", {
  sp <- set_priors(phi = prior("student_t", 0, 0.3, df = 5))
  expect_equal(sp$phi$family_int, 2L)
  expect_equal(sp$phi$df, 5)
  expect_true(sp$beta$is_default)
})

test_that("passing non-bvarnet_prior to set_priors() stops", {
  expect_error(set_priors(beta = "normal"), "bvarnet_prior")
  expect_error(set_priors(phi  = list(family = "normal")), "bvarnet_prior")
})


# ═════════════════════════════════════════════════════════════════════════════
# §3 — format.bvarnet_prior() and print.bvarnet_priors()
# ═════════════════════════════════════════════════════════════════════════════

test_that("format(prior('normal', 0, 1)) equals 'Normal(0, 1)'", {
  expect_equal(format(prior("normal", 0, 1)), "Normal(0, 1)")
})

test_that("format with half = TRUE prepends 'Half-'", {
  expect_equal(format(prior("normal", 0, 1), half = TRUE), "Half-Normal(0, 1)")
})

test_that("format(prior('student_t', ...)) contains 'Student-t'", {
  expect_match(format(prior("student_t", 0, 1, df = 7)), "Student-t")
})

test_that("format(prior('cauchy', ...)) contains 'Cauchy'", {
  expect_match(format(prior("cauchy", 0, 1)), "Cauchy")
})

test_that("print(set_priors()) shows 'all defaults' message", {
  out <- capture.output(print(set_priors()))
  expect_true(any(grepl("all defaults", out)))
})

test_that("print(set_priors()) does not show individual prior lines when all defaults", {
  out <- capture.output(print(set_priors()))
  # Should NOT have individual "beta ~" lines
  expect_false(any(grepl("^\\s*beta\\s+~", out)))
})

test_that("print with one user prior shows only that prior", {
  sp <- set_priors(beta = prior("cauchy", 0, 2))
  out <- capture.output(print(sp))
  # beta should appear on its own line
  expect_true(any(grepl("^\\s*beta\\s+~", out)))
  # defaults should NOT appear
  expect_false(any(grepl("phi", out)))
  expect_false(any(grepl("sd_u", out)))
  expect_false(any(grepl("Defaults:", out)))
})

test_that("print with multiple user priors shows only those", {
  sp <- set_priors(
    beta = prior("cauchy", 0, 2),
    phi  = prior("student_t", 0, 0.3, df = 5)
  )
  out <- capture.output(print(sp))
  expect_true(any(grepl("beta", out)))
  expect_true(any(grepl("phi", out)))
  expect_false(any(grepl("sd_u", out)))
  expect_false(any(grepl("sigma", out)))
})

test_that("print with all user-set priors shows all of them", {
  sp <- set_priors(
    beta  = prior("normal", 0, 2),
    phi   = prior("normal", 0, 1),
    sd_u  = prior("cauchy", 0, 1),
    kappa = prior("normal", 0, 3),
    sigma = prior("cauchy", 0, 2)
  )
  out <- capture.output(print(sp))
  expect_false(any(grepl("all defaults", out)))
  expect_true(any(grepl("beta",  out)))
  expect_true(any(grepl("phi",   out)))
  expect_true(any(grepl("sd_u",  out)))
  expect_true(any(grepl("sigma", out)))
  expect_true(any(grepl("kappa", out)))
})


# ═════════════════════════════════════════════════════════════════════════════
# §4 — get_default_priors()
# ═════════════════════════════════════════════════════════════════════════════

test_that("get_default_priors('bernoulli') returns a bvarnet_priors object", {
  expect_s3_class(get_default_priors("bernoulli"), "bvarnet_priors")
})

test_that("get_default_priors('ordinal') has a kappa slot", {
  sp <- get_default_priors("ordinal")
  expect_true("kappa" %in% names(sp))
  expect_s3_class(sp$kappa, "bvarnet_prior")
})

test_that("get_default_priors('gaussian') has a sigma slot", {
  sp <- get_default_priors("gaussian")
  expect_true("sigma" %in% names(sp))
  expect_s3_class(sp$sigma, "bvarnet_prior")
})

test_that("get_default_priors() with invalid family stops", {
  expect_error(get_default_priors("poisson"), "arg")
})

test_that("get_default_priors('bernoulli') omits sigma and kappa", {
  sp <- get_default_priors("bernoulli")
  expect_null(sp$sigma)
  expect_null(sp$kappa)
  expect_true("beta" %in% names(sp))
  expect_true("phi"  %in% names(sp))
  expect_true("sd_u" %in% names(sp))
})

test_that("get_default_priors('gaussian') omits kappa but keeps sigma", {
  sp <- get_default_priors("gaussian")
  expect_null(sp$kappa)
  expect_true("sigma" %in% names(sp))
})

test_that("get_default_priors('ordinal') omits sigma but keeps kappa", {
  sp <- get_default_priors("ordinal")
  expect_null(sp$sigma)
  expect_true("kappa" %in% names(sp))
})

test_that("get_default_priors(has_re = FALSE) omits sd_u", {
  sp <- get_default_priors("bernoulli", has_re = FALSE)
  expect_null(sp$sd_u)
  expect_true("beta" %in% names(sp))
  expect_true("phi"  %in% names(sp))
})

test_that("get_default_priors() with no args returns all six", {
  sp <- get_default_priors()
  expect_named(sp, c("intercept", "beta", "phi", "sd_u", "kappa", "sigma"))
})


# ═════════════════════════════════════════════════════════════════════════════
# §5 — .ensure_prior_slots()
# ═════════════════════════════════════════════════════════════════════════════

test_that(".ensure_prior_slots fills missing sigma for gaussian family", {
  p <- get_default_priors("bernoulli")  # no sigma
  family_vec <- c(y_1 = "gaussian")
  expect_warning(
    filled <- bvarnet:::.ensure_prior_slots(p, family_vec),
    "sigma"
  )
  expect_s3_class(filled$sigma, "bvarnet_prior")
  expect_true(filled$sigma$is_default)
})

test_that(".ensure_prior_slots fills missing kappa for ordinal family", {
  p <- get_default_priors("bernoulli")  # no kappa
  family_vec <- c(y_1 = "ordinal")
  expect_warning(
    filled <- bvarnet:::.ensure_prior_slots(p, family_vec),
    "kappa"
  )
  expect_s3_class(filled$kappa, "bvarnet_prior")
})

test_that(".ensure_prior_slots fills missing sd_u from filtered object", {
  p <- get_default_priors("bernoulli", has_re = FALSE)  # no sd_u
  family_vec <- c(y_1 = "bernoulli")
  expect_warning(
    filled <- bvarnet:::.ensure_prior_slots(p, family_vec),
    "sd_u"
  )
  expect_s3_class(filled$sd_u, "bvarnet_prior")
})

test_that(".ensure_prior_slots does nothing for complete priors", {
  p <- set_priors()
  family_vec <- c(y_1 = "gaussian", y_2 = "ordinal")
  # No warning expected
  expect_silent(bvarnet:::.ensure_prior_slots(p, family_vec))
})


# ═════════════════════════════════════════════════════════════════════════════
# §6 — .prior_warnings()
# ═════════════════════════════════════════════════════════════════════════════

test_that(".prior_warnings returns correct needed set for bernoulli without REs", {
  p <- set_priors()
  needed <- bvarnet:::.prior_warnings(p, c(y_1 = "bernoulli"), n_re = 0L)
  expect_equal(needed, c("intercept", "beta", "phi"))
})

test_that(".prior_warnings returns correct needed set for gaussian with REs", {
  p <- set_priors()
  needed <- bvarnet:::.prior_warnings(p, c(y_1 = "gaussian"), n_re = 2L)
  expect_equal(needed, c("intercept", "beta", "phi", "sd_u", "sigma"))
})

test_that(".prior_warnings returns correct needed set for ordinal", {
  p <- set_priors()
  needed <- bvarnet:::.prior_warnings(p, c(y_1 = "ordinal"), n_re = 0L)
  expect_equal(needed, c("beta", "phi", "kappa"))
})

test_that(".prior_warnings warns about unused user-set priors", {
  p <- set_priors(sigma = prior("cauchy", 0, 2))
  expect_warning(
    bvarnet:::.prior_warnings(p, c(y_1 = "bernoulli"), n_re = 0L),
    "not used.*sigma"
  )
})

test_that(".prior_warnings warns about unused sd_u when no REs", {
  p <- set_priors(sd_u = prior("cauchy", 0, 1))
  expect_warning(
    bvarnet:::.prior_warnings(p, c(y_1 = "bernoulli"), n_re = 0L),
    "not used.*sd_u"
  )
})

test_that(".prior_warnings messages about auto-filled defaults", {
  p <- set_priors(beta = prior("cauchy", 0, 2))
  expect_message(
    bvarnet:::.prior_warnings(p, c(y_1 = "gaussian"), n_re = 0L),
    "Using default priors for: intercept, phi, sigma"
  )
})

test_that(".prior_warnings does NOT message when all priors are defaults", {
  p <- set_priors()
  expect_silent(
    bvarnet:::.prior_warnings(p, c(y_1 = "gaussian"), n_re = 0L)
  )
})

test_that(".prior_warnings does NOT message when all needed priors are user-set", {
  p <- set_priors(
    beta      = prior("cauchy", 0, 2),
    intercept = prior("normal", 0, 1),
    phi       = prior("normal", 0, 0.3)
  )
  expect_silent(
    bvarnet:::.prior_warnings(p, c(y_1 = "bernoulli"), n_re = 0L)
  )
})
