test_that("read_close_series reads exact close column", {
  tmp <- tempfile(fileext = ".csv")
  on.exit(unlink(tmp), add = TRUE)

  dat <- data.frame(
    date = sprintf("2026-03-%02d", 1:12),
    close = c(100, 100.5, 100.2, 100.8, 101.0, 100.9,
              101.3, 101.1, 101.6, 101.4, 101.9, 102.0)
  )

  utils::write.csv(dat, tmp, row.names = FALSE)

  px <- read_close_series(tmp, close_col = "close")

  expect_type(px, "double")
  expect_equal(length(px), 12L)
  expect_true(all(is.finite(px)))
  expect_equal(px[1], 100)
  expect_equal(px[12], 102.0)
})

test_that("read_close_series reads case-insensitive close column", {
  tmp <- tempfile(fileext = ".csv")
  on.exit(unlink(tmp), add = TRUE)

  dat <- data.frame(
    date = sprintf("2026-03-%02d", 1:12),
    Close = c(100, 100.5, 100.2, 100.8, 101.0, 100.9,
              101.3, 101.1, 101.6, 101.4, 101.9, 102.0)
  )

  utils::write.csv(dat, tmp, row.names = FALSE)

  px <- read_close_series(tmp, close_col = "close")

  expect_type(px, "double")
  expect_equal(length(px), 12L)
  expect_true(all(is.finite(px)))
})

test_that("read_close_series falls back to column names containing close", {
  tmp <- tempfile(fileext = ".csv")
  on.exit(unlink(tmp), add = TRUE)

  dat <- data.frame(
    date = sprintf("2026-03-%02d", 1:12),
    adjusted_close = c(100, 100.5, 100.2, 100.8, 101.0, 100.9,
                       101.3, 101.1, 101.6, 101.4, 101.9, 102.0)
  )

  utils::write.csv(dat, tmp, row.names = FALSE)

  px <- read_close_series(tmp, close_col = "close")

  expect_type(px, "double")
  expect_equal(length(px), 12L)
  expect_true(all(is.finite(px)))
})

test_that("read_close_series errors when no close-like column exists", {
  tmp <- tempfile(fileext = ".csv")
  on.exit(unlink(tmp), add = TRUE)

  dat <- data.frame(
    date = sprintf("2026-03-%02d", 1:12),
    settle = c(100, 100.5, 100.2, 100.8, 101.0, 100.9,
               101.3, 101.1, 101.6, 101.4, 101.9, 102.0)
  )

  utils::write.csv(dat, tmp, row.names = FALSE)

  expect_error(
    read_close_series(tmp, close_col = "close"),
    regexp = "close|column|found",
    ignore.case = TRUE
  )
})

test_that("read_close_series errors on non-numeric close column", {
  tmp <- tempfile(fileext = ".csv")
  on.exit(unlink(tmp), add = TRUE)

  dat <- data.frame(
    date = sprintf("2026-03-%02d", 1:12),
    close = rep("abc", 12),
    stringsAsFactors = FALSE
  )

  utils::write.csv(dat, tmp, row.names = FALSE)

  expect_error(
    read_close_series(tmp, close_col = "close"),
    regexp = "numeric|finite|close",
    ignore.case = TRUE
  )
})

test_that("read_close_series errors when too few usable prices remain", {
  tmp <- tempfile(fileext = ".csv")
  on.exit(unlink(tmp), add = TRUE)

  dat <- data.frame(
    date = c("2026-03-01", "2026-03-02"),
    close = c(100, 101)
  )

  utils::write.csv(dat, tmp, row.names = FALSE)

  expect_error(
    read_close_series(tmp, close_col = "close"),
    regexp = "at least|enough|observations|length",
    ignore.case = TRUE
  )
})

test_that("compute_log_returns returns expected length and finite values", {
  px <- c(100, 100.5, 100.2, 100.8, 101.0, 100.9)

  ret <- compute_log_returns(px)

  expect_type(ret, "double")
  expect_equal(length(ret), length(px) - 1L)
  expect_true(all(is.finite(ret)))
})

test_that("compute_log_returns errors on non-positive prices", {
  px <- c(100, 101, 0, 102)

  expect_error(
    compute_log_returns(px),
    regexp = "positive|non-positive|price",
    ignore.case = TRUE
  )
})

test_that("compute_log_returns errors on too-short input", {
  expect_error(
    compute_log_returns(100),
    regexp = "Not enough valid returns|need >= 10|at least|length|observations",
    ignore.case = TRUE
  )
})