test_that("run_kronx works on a small numeric return series", {
  skip_on_cran()

  set.seed(123)
  x <- rnorm(120, mean = 0, sd = 0.01)

  res <- run_kronx(
    x = x,
    K = 2L,
    n_starts = 1L,
    max_iter = 10L,
    tol = 1e-4,
    tail_alpha = 0.05,
    ruin_horizon = 25L,
    verbose = FALSE,
    output_dir = NULL
  )

  expect_type(res, "list")
  expect_named(
    res,
    c(
      "close_px", "ret", "K", "gauss_fit", "t_fit", "A_gauss", "A_t",
      "epsilon", "Q", "K_mat", "N_mat", "pi_qs", "pi_res",
      "loss_threshold", "q_state", "bar_q", "bar_lambda", "ruin_bound",
      "tail_alpha", "ruin_horizon", "state_summary", "vpath_t",
      "output_files", "input_source"
    ),
    ignore.order = TRUE
  )

  expect_null(res$close_px)
  expect_equal(res$K, 2L)
  expect_equal(length(res$ret), length(x))
  expect_identical(res$output_files, NULL)
  expect_identical(res$input_source, "supplied numeric return series")
})

test_that("run_kronx returns matrices and vectors with consistent dimensions", {
  skip_on_cran()

  set.seed(456)
  x <- rnorm(150, mean = 0, sd = 0.012)

  res <- run_kronx(
    x = x,
    K = 2L,
    n_starts = 1L,
    max_iter = 10L,
    tol = 1e-4,
    tail_alpha = 0.05,
    ruin_horizon = 20L,
    verbose = FALSE,
    output_dir = NULL
  )

  expect_equal(dim(res$A_gauss), c(2L, 2L))
  expect_equal(dim(res$A_t), c(2L, 2L))
  expect_equal(dim(res$Q), c(2L, 2L))
  expect_equal(dim(res$K_mat), c(2L, 2L))
  expect_equal(dim(res$N_mat), c(2L, 2L))

  expect_length(res$epsilon, 2L)
  expect_length(res$pi_qs, 2L)
  expect_length(res$pi_res, 2L)
  expect_length(res$q_state, 2L)
  expect_length(res$vpath_t, length(x))

  expect_true(is.data.frame(res$state_summary))
  expect_equal(nrow(res$state_summary), 2L)
})

test_that("run_kronx returns finite scalar risk summaries", {
  skip_on_cran()

  set.seed(789)
  x <- rnorm(100, mean = 0, sd = 0.01)

  res <- run_kronx(
    x = x,
    K = 2L,
    n_starts = 1L,
    max_iter = 8L,
    tol = 1e-4,
    tail_alpha = 0.05,
    ruin_horizon = 15L,
    verbose = FALSE,
    output_dir = NULL
  )

  expect_true(is.numeric(res$loss_threshold))
  expect_true(length(res$loss_threshold) == 1L)
  expect_true(is.finite(res$loss_threshold))

  expect_true(is.numeric(res$bar_q))
  expect_true(length(res$bar_q) == 1L)
  expect_true(is.finite(res$bar_q))
  expect_gte(res$bar_q, 0)

  expect_true(is.numeric(res$bar_lambda))
  expect_true(length(res$bar_lambda) == 1L)
  expect_true(is.finite(res$bar_lambda))
  expect_gte(res$bar_lambda, 0)

  expect_true(is.numeric(res$ruin_bound))
  expect_true(length(res$ruin_bound) == 1L)
  expect_true(is.finite(res$ruin_bound))
  expect_gte(res$ruin_bound, 0)
  expect_lte(res$ruin_bound, 1)
})

test_that("run_kronx returns probability-like weights that sum to one", {
  skip_on_cran()

  set.seed(321)
  x <- rnorm(120, mean = 0, sd = 0.009)

  res <- run_kronx(
    x = x,
    K = 2L,
    n_starts = 1L,
    max_iter = 10L,
    tol = 1e-4,
    tail_alpha = 0.05,
    ruin_horizon = 25L,
    verbose = FALSE,
    output_dir = NULL
  )

  expect_equal(sum(res$pi_qs), 1, tolerance = 1e-6)
  expect_equal(sum(res$pi_res), 1, tolerance = 1e-6)

  expect_true(all(is.finite(res$pi_qs)))
  expect_true(all(is.finite(res$pi_res)))
  expect_true(all(res$pi_qs >= 0))
  expect_true(all(res$pi_res >= 0))
})

test_that("run_kronx rejects missing inputs", {
  expect_error(
    run_kronx(verbose = FALSE, output_dir = NULL),
    "Provide either 'file' or 'x'"
  )
})

test_that("run_kronx rejects too-short numeric input", {
  expect_error(
    run_kronx(
      x = c(0.01, -0.02, 0.03),
      verbose = FALSE,
      output_dir = NULL
    ),
    "at least 10"
  )
})

test_that("run_kronx rejects invalid tail_alpha", {
  set.seed(111)
  x <- rnorm(50, 0, 0.01)

  expect_error(
    run_kronx(
      x = x,
      tail_alpha = 1,
      verbose = FALSE,
      output_dir = NULL
    ),
    "tail_alpha"
  )

  expect_error(
    run_kronx(
      x = x,
      tail_alpha = 0,
      verbose = FALSE,
      output_dir = NULL
    ),
    "tail_alpha"
  )
})

test_that("run_kronx can write outputs when requested", {
  skip_on_cran()

  set.seed(222)
  x <- rnorm(100, mean = 0, sd = 0.01)
  outdir <- file.path(tempdir(), "kronx_test_output")

  if (dir.exists(outdir)) {
    unlink(outdir, recursive = TRUE, force = TRUE)
  }

  res <- run_kronx(
    x = x,
    K = 2L,
    n_starts = 1L,
    max_iter = 8L,
    tol = 1e-4,
    tail_alpha = 0.05,
    ruin_horizon = 20L,
    verbose = FALSE,
    output_dir = outdir
  )

  expect_true(dir.exists(outdir))
  expect_true(is.character(res$output_files))
  expect_true(length(res$output_files) >= 1L)
  expect_true(all(file.exists(res$output_files)))

  unlink(outdir, recursive = TRUE, force = TRUE)
})