library(testthat)
library(DataAudit)

#==========================================================
# Basic output
#==========================================================

test_that("missing_check returns MissingCheck object", {

  result <- missing_check(iris)

  expect_s3_class(
    result,
    "MissingCheck"
  )

})

test_that("missing_check returns data.frame", {

  result <- missing_check(iris)

  expect_s3_class(
    result,
    "data.frame"
  )

})

test_that("missing_check contains expected columns", {

  result <- missing_check(iris)

  expect_equal(
    names(result),
    c(
      "Variable",
      "Total",
      "Missing",
      "Complete",
      "MissingPercent",
      "CompletePercent"
    )
  )

})

test_that("missing_check returns one row per variable", {

  result <- missing_check(iris)

  expect_equal(
    nrow(result),
    ncol(iris)
  )

})


#==========================================================
# Complete dataset
#==========================================================

test_that("missing_check reports zero missing values for iris", {

  result <- missing_check(iris)

  expect_true(
    all(result$Missing == 0L)
  )

})

test_that("missing_check reports correct totals for iris", {

  result <- missing_check(iris)

  expect_true(
    all(result$Total == 150L)
  )

  expect_true(
    all(result$Complete == 150L)
  )

})

test_that("missing_check reports correct percentages for complete data", {

  result <- missing_check(iris)

  expect_true(
    all(result$MissingPercent == 0)
  )

  expect_true(
    all(result$CompletePercent == 100)
  )

})


#==========================================================
# Missing values
#==========================================================

test_that("missing_check counts missing values correctly", {

  dat <- iris

  dat$Sepal.Length[1:10] <- NA
  dat$Species[1:5] <- NA

  result <- missing_check(dat)

  expect_equal(
    result$Missing[
      result$Variable == "Sepal.Length"
    ],
    10L
  )

  expect_equal(
    result$Missing[
      result$Variable == "Species"
    ],
    5L
  )

})

test_that("missing_check counts complete values correctly", {

  dat <- iris

  dat$Sepal.Length[1:10] <- NA

  result <- missing_check(dat)

  expect_equal(
    result$Complete[
      result$Variable == "Sepal.Length"
    ],
    140L
  )

})

test_that("missing_check calculates missing percentage correctly", {

  dat <- data.frame(
    x = c(1, NA, 3, NA)
  )

  result <- missing_check(dat)

  expect_equal(
    result$MissingPercent,
    50
  )

  expect_equal(
    result$CompletePercent,
    50
  )

})

test_that("missing_check rounds percentages to two decimal places", {

  dat <- data.frame(
    x = c(1, 2, NA)
  )

  result <- missing_check(dat)

  expect_equal(
    result$MissingPercent,
    33.33
  )

  expect_equal(
    result$CompletePercent,
    66.67
  )

})


#==========================================================
# All missing
#==========================================================

test_that("missing_check handles completely missing variable", {

  dat <- data.frame(
    x = rep(
      NA_real_,
      5
    )
  )

  result <- missing_check(dat)

  expect_equal(
    result$Missing,
    5L
  )

  expect_equal(
    result$Complete,
    0L
  )

  expect_equal(
    result$MissingPercent,
    100
  )

  expect_equal(
    result$CompletePercent,
    0
  )

})


#==========================================================
# Mixed variable types
#==========================================================

test_that("missing_check handles mixed variable types", {

  dat <- data.frame(
    numeric = c(1, NA, 3, 4),
    character = c("A", "B", NA, "D"),
    factor = factor(
      c("Low", NA, "High", "Low")
    ),
    logical = c(TRUE, FALSE, NA, TRUE),
    stringsAsFactors = FALSE
  )

  result <- missing_check(dat)

  expect_equal(
    result$Missing,
    rep(1L, 4)
  )

  expect_equal(
    result$Complete,
    rep(3L, 4)
  )

  expect_equal(
    result$MissingPercent,
    rep(25, 4)
  )

})


#==========================================================
# Character blanks
#==========================================================

test_that("missing_check does not treat blank strings as missing", {

  dat <- data.frame(
    x = c(
      "A",
      "",
      " ",
      NA
    ),
    stringsAsFactors = FALSE
  )

  result <- missing_check(dat)

  expect_equal(
    result$Missing,
    1L
  )

})


#==========================================================
# Date
#==========================================================

test_that("missing_check handles Date variables", {

  dat <- data.frame(
    date = as.Date(
      c(
        "2026-01-01",
        NA,
        "2026-01-03"
      )
    )
  )

  result <- missing_check(dat)

  expect_equal(
    result$Missing,
    1L
  )

  expect_equal(
    result$Complete,
    2L
  )

})


#==========================================================
# POSIXct
#==========================================================

test_that("missing_check handles POSIXct variables", {

  x <- as.POSIXct(
    c(
      "2026-01-01 10:00:00",
      "2026-01-02 10:00:00",
      "2026-01-03 10:00:00"
    ),
    tz = "UTC"
  )

  x[2] <- NA

  dat <- data.frame(
    time = x
  )

  result <- missing_check(dat)

  expect_equal(
    result$Missing,
    1L
  )

  expect_equal(
    result$Complete,
    2L
  )

})


#==========================================================
# One-column data
#==========================================================

test_that("missing_check handles one-column data", {

  dat <- data.frame(
    x = c(
      1,
      NA,
      3,
      4
    )
  )

  result <- missing_check(dat)

  expect_equal(
    nrow(result),
    1L
  )

  expect_equal(
    result$Variable,
    "x"
  )

  expect_equal(
    result$Total,
    4L
  )

  expect_equal(
    result$Missing,
    1L
  )

})


#==========================================================
# Zero-row data
#==========================================================

test_that("missing_check handles zero-row data", {

  dat <- data.frame(
    x = numeric(0),
    y = character(0)
  )

  result <- missing_check(dat)

  expect_equal(
    nrow(result),
    2L
  )

  expect_true(
    all(result$Total == 0L)
  )

  expect_true(
    all(result$Missing == 0L)
  )

  expect_true(
    all(result$Complete == 0L)
  )

  expect_true(
    all(is.na(result$MissingPercent))
  )

  expect_true(
    all(is.na(result$CompletePercent))
  )

})


#==========================================================
# Tibble
#==========================================================

test_that("missing_check handles tibble", {

  skip_if_not_installed("tibble")

  dat <- tibble::as_tibble(iris)

  result <- missing_check(dat)

  expect_s3_class(
    result,
    "MissingCheck"
  )

  expect_equal(
    nrow(result),
    5L
  )

})


#==========================================================
# Column names
#==========================================================

test_that("missing_check preserves variable names", {

  dat <- data.frame(
    First = 1:3,
    Second = 4:6
  )

  result <- missing_check(dat)

  expect_equal(
    result$Variable,
    c(
      "First",
      "Second"
    )
  )

})


#==========================================================
# Invalid input
#==========================================================

test_that("missing_check rejects NULL", {

  expect_error(
    missing_check(NULL),
    "'data' cannot be NULL"
  )

})

test_that("missing_check rejects numeric vector", {

  expect_error(
    missing_check(1:10),
    "'data' must be a data.frame"
  )

})

test_that("missing_check rejects character vector", {

  expect_error(
    missing_check(letters),
    "'data' must be a data.frame"
  )

})

test_that("missing_check rejects list", {

  expect_error(
    missing_check(
      list(
        x = 1:5,
        y = 6:10
      )
    ),
    "'data' must be a data.frame"
  )

})

test_that("missing_check rejects empty data.frame", {

  expect_error(
    missing_check(
      data.frame()
    ),
    "at least one variable"
  )

})
