test_that("alphaF equals one-year term APV", {
  expect_equal(
    alphaF(40, i = 0.05, model = "uniform", omega = 100),
    Axn1(40, n = 1, i = 0.05, model = "uniform", omega = 100),
    tolerance = 1e-12
  )
})

test_that("betaF equals premium at age x+1", {
  expect_equal(
    betaF(40, i = 0.05, model = "uniform", omega = 100),
    Px(41, i = 0.05, model = "uniform", omega = 100),
    tolerance = 1e-12
  )
})

test_that("FPT whole life reserve is zero in years 0 and 1", {
  expect_equal(
    tVFx(40, t = 0, i = 0.05, model = "uniform", omega = 100),
    0,
    tolerance = 1e-12
  )

  expect_equal(
    tVFx(40, t = 1, i = 0.05, model = "uniform", omega = 100),
    0,
    tolerance = 1e-12
  )
})

test_that("FPT whole life reserve shifts to NLP reserve at age x+1", {
  expect_equal(
    tVFx(40, t = 5, i = 0.05, model = "uniform", omega = 100),
    tVx(41, t = 4, i = 0.05, model = "uniform", omega = 100),
    tolerance = 1e-10
  )
})

test_that("fractional whole life reserve gives initial reserve at s = 0", {
  x <- 40
  t <- 10
  i <- 0.05

  expect_equal(
    tsVx(x, t = t, s = 0, i = i, model = "uniform", omega = 100),
    tVx(x, t = t, i = i, model = "uniform", omega = 100) +
      Px(x, i = i, model = "uniform", omega = 100),
    tolerance = 1e-10
  )
})

test_that("fractional whole life reserve gives next terminal reserve at s = 1", {
  x <- 40
  t <- 10
  i <- 0.05

  expect_equal(
    tsVx(x, t = t, s = 1, i = i, model = "uniform", omega = 100),
    tVx(x, t = t + 1, i = i, model = "uniform", omega = 100),
    tolerance = 1e-10
  )
})

test_that("meanVx matches tsVx at s = 0.5", {
  expect_equal(
    meanVx(40, t = 10, i = 0.05, model = "uniform", omega = 100),
    tsVx(40, t = 10, s = 0.5, i = 0.05, model = "uniform", omega = 100),
    tolerance = 1e-12
  )
})

test_that("fractional endowment reserve gives correct endpoints", {
  x <- 40
  n <- 20
  t <- 10
  i <- 0.05

  expect_equal(
    tsVxn(x, n = n, t = t, s = 0, i = i, model = "uniform", omega = 100),
    tVxn(x, n = n, t = t, i = i, model = "uniform", omega = 100) +
      Pxn(x, n = n, i = i, model = "uniform", omega = 100),
    tolerance = 1e-10
  )

  expect_equal(
    tsVxn(x, n = n, t = t, s = 1, i = i, model = "uniform", omega = 100),
    tVxn(x, n = n, t = t + 1, i = i, model = "uniform", omega = 100),
    tolerance = 1e-10
  )
})

test_that("fractional term reserve gives correct endpoints", {
  x <- 40
  n <- 20
  t <- 10
  i <- 0.05

  expect_equal(
    tsVxn1(x, n = n, t = t, s = 0, i = i, model = "uniform", omega = 100),
    tVxn1(x, n = n, t = t, i = i, model = "uniform", omega = 100) +
      Pxn1(x, n = n, i = i, model = "uniform", omega = 100),
    tolerance = 1e-10
  )

  expect_equal(
    tsVxn1(x, n = n, t = t, s = 1, i = i, model = "uniform", omega = 100),
    tVxn1(x, n = n, t = t + 1, i = i, model = "uniform", omega = 100),
    tolerance = 1e-10
  )
})

test_that("gross reserve equals net reserve plus expense reserve", {
  x <- 40
  t <- 10
  i <- 0.05
  G <- 0.04
  benefit <- 1
  r <- 0.10
  e <- 0.002
  s <- 0.02

  expect_equal(
    tVGx(
      x = x, t = t, i = i, G = G, benefit = benefit,
      renewal_premium_pct = r,
      renewal_policy_exp = e,
      settlement_exp = s,
      model = "uniform", omega = 100
    ),
    benefit * tVx(x, t = t, i = i, model = "uniform", omega = 100) +
      tVEx(
        x = x, t = t, i = i, G = G, benefit = benefit,
        renewal_premium_pct = r,
        renewal_policy_exp = e,
        settlement_exp = s,
        model = "uniform", omega = 100
      ),
    tolerance = 1e-10
  )
})

test_that("gross total gain reproduces Example 11.9 value", {
  gt <- GTg_disc(
    VtG = 3950.73,
    Vt1G = 4607.07,
    G = 685.00,
    i_actual = 0.065,
    q_actual = 0.005,
    r_actual = 0.06,
    e_actual = 0,
    s_actual = 100,
    b = 50000
  )

  expect_equal(gt, 58.75, tolerance = 0.02)
})

test_that("ordered gross gain decomposition sums to total gain", {
  out <- decompGg_disc(
    VtG = 3950.73,
    Vt1G = 4607.07,
    G = 685.00,
    i_assumed = 0.06,
    q_assumed = 0.00592,
    r_assumed = 0.05,
    e_assumed = 0,
    s_assumed = 300,
    i_actual = 0.065,
    q_actual = 0.005,
    r_actual = 0.06,
    e_actual = 0,
    s_actual = 100,
    b = 50000,
    order = c("interest", "mortality", "expense")
  )

  expect_equal(
    unname(out["total_gain"]),
    unname(out["check"]),
    tolerance = 1e-10
  )
})

test_that("different decomposition orders still sum to same total gain", {
  out1 <- decompGg_disc(
    VtG = 3950.73,
    Vt1G = 4607.07,
    G = 685.00,
    i_assumed = 0.06,
    q_assumed = 0.00592,
    r_assumed = 0.05,
    e_assumed = 0,
    s_assumed = 300,
    i_actual = 0.065,
    q_actual = 0.005,
    r_actual = 0.06,
    e_actual = 0,
    s_actual = 100,
    b = 50000,
    order = c("interest", "mortality", "expense")
  )

  out2 <- decompGg_disc(
    VtG = 3950.73,
    Vt1G = 4607.07,
    G = 685.00,
    i_assumed = 0.06,
    q_assumed = 0.00592,
    r_assumed = 0.05,
    e_assumed = 0,
    s_assumed = 300,
    i_actual = 0.065,
    q_actual = 0.005,
    r_actual = 0.06,
    e_actual = 0,
    s_actual = 100,
    b = 50000,
    order = c("mortality", "expense", "interest")
  )

  expect_equal(
    unname(out1["total_gain"]),
    unname(out2["total_gain"]),
    tolerance = 1e-12
  )

  expect_equal(
    unname(out2["total_gain"]),
    unname(out2["check"]),
    tolerance = 1e-10
  )
})

test_that("Chapter 11 functions reject invalid inputs", {
  expect_error(
    tsVx(40, t = 10, s = 1.2, i = 0.05, model = "uniform", omega = 100),
    "s must contain values in \\[0, 1\\]"
  )

  expect_error(
    tsVxn(40, n = 10, t = 10, s = 0.5, i = 0.05, model = "uniform", omega = 100),
    "t must satisfy t < n"
  )

  expect_error(
    decompGg_disc(
      VtG = 1, Vt1G = 1, G = 1,
      i_assumed = 0.05, q_assumed = 0.01,
      r_assumed = 0.03, e_assumed = 0, s_assumed = 0,
      i_actual = 0.06, q_actual = 0.02,
      r_actual = 0.04, e_actual = 0, s_actual = 0,
      order = c("interest", "interest", "expense")
    ),
    "exactly once"
  )
})
