# Tests for input validation of the exported model functions.
# IsingSampler() previously used an OR guard so supplying only 'graph' or only
# 'thresholds' passed and then failed with an obscure error. These tests assert
# the specific, clear error messages and confirm valid calls still work.
# Plain stopifnot tests, no package dependencies beyond IsingSampler itself.

library("IsingSampler")

set.seed(1)

## Small valid model ----------------------------------------------------------
N <- 3
graph <- matrix(0, N, N)
graph[upper.tri(graph)] <- runif(N * (N - 1) / 2, -0.5, 1)
graph <- graph + t(graph)
thresholds <- runif(N, -1, 1)

# Helper: run 'expr' and return the error message (or NA if no error).
errMsg <- function(expr) tryCatch({ force(expr); NA_character_ },
                                  error = function(e) conditionMessage(e))

## 1) Missing graph -----------------------------------------------------------
stopifnot(errMsg(IsingSampler(10, thresholds = thresholds)) == "'graph' must be supplied.")

## 2) Missing thresholds ------------------------------------------------------
stopifnot(errMsg(IsingSampler(10, graph = graph)) == "'thresholds' must be supplied.")

## 3) Non-square graph --------------------------------------------------------
badGraph <- matrix(0, 3, 2)
stopifnot(errMsg(IsingSampler(10, badGraph, c(0, 0))) == "'graph' must be a numeric square matrix.")

## 4) Threshold length mismatch -----------------------------------------------
stopifnot(errMsg(IsingSampler(10, graph, c(0, 0))) ==
            "'thresholds' must have length 1 or the number of nodes (ncol(graph)).")

## 5) Non-integer / negative n ------------------------------------------------
stopifnot(errMsg(IsingSampler(2.5, graph, thresholds)) == "'n' must be a single positive integer.")
stopifnot(errMsg(IsingSampler(-1, graph, thresholds)) == "'n' must be a single positive integer.")
stopifnot(errMsg(IsingSampler(c(1, 2), graph, thresholds)) == "'n' must be a single positive integer.")

## 6) Invalid beta ------------------------------------------------------------
stopifnot(errMsg(IsingSampler(10, graph, thresholds, beta = c(1, 2))) ==
            "'beta' must be a single finite numeric value.")
stopifnot(errMsg(IsingSampler(10, graph, thresholds, beta = Inf)) ==
            "'beta' must be a single finite numeric value.")

## 7) Invalid nIter -----------------------------------------------------------
stopifnot(errMsg(IsingSampler(10, graph, thresholds, nIter = 2.5)) ==
            "'nIter' must be a single positive integer.")

## 8) IsingStateProb with asymmetric graph ------------------------------------
asym <- graph
asym[1, 2] <- asym[1, 2] + 1  # break symmetry
msg <- errMsg(IsingStateProb(rep(0L, N), asym, thresholds, beta = 1))
stopifnot(grepl("symmetric", msg) || grepl("isSymmetric", msg))

## 9) IsingStateProb with wrong state length ----------------------------------
stopifnot(errMsg(IsingStateProb(rep(0L, N + 1), graph, thresholds, beta = 1)) ==
            "Each state in 's' must have length equal to the number of nodes (ncol(graph)).")

## 10) Distribution functions reject non-square graph -------------------------
stopifnot(errMsg(IsingLikelihood(badGraph, c(0, 0), beta = 1)) ==
            "'graph' must be a numeric square matrix.")
stopifnot(errMsg(IsingSumLikelihood(badGraph, c(0, 0), beta = 1)) ==
            "'graph' must be a numeric square matrix.")

## Valid calls still work (smoke tests) ---------------------------------------
samples <- IsingSampler(10, graph, thresholds)
stopifnot(is.matrix(samples), nrow(samples) == 10, ncol(samples) == N)

samplesDir <- IsingSampler(10, graph, thresholds, method = "direct")
stopifnot(is.matrix(samplesDir), nrow(samplesDir) == 10, ncol(samplesDir) == N)

lik <- IsingLikelihood(graph, thresholds, beta = 1)
stopifnot(is.data.frame(lik))

sumLik <- IsingSumLikelihood(graph, thresholds, beta = 1)
stopifnot(is.data.frame(sumLik))

p <- IsingStateProb(rep(0L, N), graph, thresholds, beta = 1)
stopifnot(is.numeric(p), length(p) == 1)

## 11) LinTransform argument validation ---------------------------------------
# Wrong 'from' / 'to' lengths must error clearly.
stopifnot(errMsg(LinTransform(graph, thresholds, from = c(0L, 1L, 2L))) ==
            "'from' and 'to' must each be vectors of length 2.")
stopifnot(errMsg(LinTransform(graph, thresholds, to = 1L)) ==
            "'from' and 'to' must each be vectors of length 2.")

# Supplying exactly one of 'a' / 'b' must error.
stopifnot(errMsg(LinTransform(graph, thresholds, a = 1)) ==
            "Supply both 'a' and 'b', or neither.")
stopifnot(errMsg(LinTransform(graph, thresholds, b = 0)) ==
            "Supply both 'a' and 'b', or neither.")

# A valid call still works.
lt <- LinTransform(graph, thresholds)
stopifnot(is.list(lt), all(c("graph", "thresholds") %in% names(lt)))

cat("All validation tests passed.\n")
