library(testthat)
library(DataAudit)

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

test_that("id_check returns IDCheck object", {

  dat <- data.frame(
    ID = c("A001", "A002")
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_s3_class(result, "IDCheck")
  expect_s3_class(result, "data.frame")
})

test_that("id_check returns expected columns", {

  dat <- data.frame(
    ID = c("A001", "A002")
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_equal(
    names(result),
    c(
      "Row",
      "Value",
      "Missing",
      "Blank",
      "WhitespaceOnly",
      "LeadingWhitespace",
      "TrailingWhitespace",
      "Duplicate",
      "PatternMismatch",
      "ValidID"
    )
  )
})

#==========================================================
# Valid identifiers
#==========================================================

test_that("valid identifiers are not flagged", {

  dat <- data.frame(
    ID = c(
      "A001",
      "A002",
      "A003"
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_true(
    all(result$ValidID)
  )

  expect_false(
    any(result$Duplicate)
  )
})

#==========================================================
# Missing and blank
#==========================================================

test_that("id_check detects missing identifiers", {

  dat <- data.frame(
    ID = c(
      "A001",
      NA,
      "A003"
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_equal(
    result$Missing,
    c(FALSE, TRUE, FALSE)
  )

  expect_false(
    result$ValidID[2]
  )
})

test_that("id_check detects blank identifiers", {

  dat <- data.frame(
    ID = c(
      "A001",
      "",
      "A003"
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_equal(
    result$Blank,
    c(FALSE, TRUE, FALSE)
  )

  expect_false(
    result$ValidID[2]
  )
})

#==========================================================
# Whitespace
#==========================================================

test_that("id_check detects whitespace-only identifiers", {

  dat <- data.frame(
    ID = c(
      "A001",
      " ",
      "   "
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_equal(
    result$WhitespaceOnly,
    c(FALSE, TRUE, TRUE)
  )

  expect_false(
    result$ValidID[2]
  )
})

test_that("id_check detects leading whitespace", {

  dat <- data.frame(
    ID = c(
      "A001",
      " A002"
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_equal(
    result$LeadingWhitespace,
    c(FALSE, TRUE)
  )
})

test_that("id_check detects trailing whitespace", {

  dat <- data.frame(
    ID = c(
      "A001",
      "A002 "
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_equal(
    result$TrailingWhitespace,
    c(FALSE, TRUE)
  )
})

#==========================================================
# Duplicates
#==========================================================

test_that("id_check flags all occurrences of duplicated IDs", {

  dat <- data.frame(
    ID = c(
      "A001",
      "A002",
      "A002",
      "A003"
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_equal(
    result$Duplicate,
    c(
      FALSE,
      TRUE,
      TRUE,
      FALSE
    )
  )

  expect_equal(
    result$ValidID,
    c(
      TRUE,
      FALSE,
      FALSE,
      TRUE
    )
  )
})

test_that("missing and blank IDs are not treated as duplicates", {

  dat <- data.frame(
    ID = c(
      NA,
      NA,
      "",
      ""
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_false(
    any(result$Duplicate)
  )
})

#==========================================================
# Pattern
#==========================================================

test_that("id_check detects pattern mismatches", {

  dat <- data.frame(
    ID = c(
      "A001",
      "A002",
      "B003",
      "A04"
    )
  )

  result <- id_check(
    dat,
    "ID",
    pattern = "^A[0-9]{3}$"
  )

  expect_equal(
    result$PatternMismatch,
    c(
      FALSE,
      FALSE,
      TRUE,
      TRUE
    )
  )
})

test_that("pattern is optional", {

  dat <- data.frame(
    ID = c(
      "ABC",
      "123"
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_false(
    any(result$PatternMismatch)
  )
})

test_that("missing blank and whitespace IDs are excluded from pattern check", {

  dat <- data.frame(
    ID = c(
      NA,
      "",
      " ",
      "A001"
    )
  )

  result <- id_check(
    dat,
    "ID",
    pattern = "^A[0-9]{3}$"
  )

  expect_false(
    any(result$PatternMismatch)
  )
})

#==========================================================
# Factor identifiers
#==========================================================

test_that("id_check supports factor identifiers", {

  dat <- data.frame(
    ID = factor(
      c(
        "A001",
        "A002",
        "A002"
      )
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_equal(
    result$Duplicate,
    c(
      FALSE,
      TRUE,
      TRUE
    )
  )
})

#==========================================================
# Numeric identifiers
#==========================================================

test_that("id_check supports numeric identifiers", {

  dat <- data.frame(
    ID = c(
      101,
      102,
      102,
      103
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_equal(
    result$Duplicate,
    c(
      FALSE,
      TRUE,
      TRUE,
      FALSE
    )
  )
})

test_that("id_check supports integer identifiers", {

  dat <- data.frame(
    ID = c(
      1L,
      2L,
      3L
    )
  )

  result <- id_check(
    dat,
    "ID"
  )

  expect_true(
    all(result$ValidID)
  )
})

#==========================================================
# Invalid variable argument
#==========================================================

test_that("id_check rejects invalid variable argument", {

  expect_error(
    id_check(iris),
    "'variable' must be a single non-empty character string"
  )

  expect_error(
    id_check(iris, NULL),
    "'variable' must be a single non-empty character string"
  )

  expect_error(
    id_check(iris, ""),
    "'variable' must be a single non-empty character string"
  )

  expect_error(
    id_check(iris, 1),
    "'variable' must be a single non-empty character string"
  )

  expect_error(
    id_check(
      iris,
      c("Species", "Sepal.Length")
    ),
    "'variable' must be a single non-empty character string"
  )

  expect_error(
    id_check(
      iris,
      NA_character_
    ),
    "'variable' must be a single non-empty character string"
  )
})

test_that("id_check rejects unknown variable", {

  expect_error(
    id_check(
      iris,
      "Unknown"
    ),
    "Variable 'Unknown' was not found in 'data'"
  )
})

#==========================================================
# Invalid pattern
#==========================================================

test_that("id_check rejects invalid pattern argument", {

  dat <- data.frame(
    ID = "A001"
  )

  expect_error(
    id_check(
      dat,
      "ID",
      pattern = ""
    ),
    "'pattern' must be NULL or a single non-empty character string"
  )

  expect_error(
    id_check(
      dat,
      "ID",
      pattern = NA_character_
    ),
    "'pattern' must be NULL or a single non-empty character string"
  )

  expect_error(
    id_check(
      dat,
      "ID",
      pattern = 1
    ),
    "'pattern' must be NULL or a single non-empty character string"
  )

  expect_error(
    id_check(
      dat,
      "ID",
      pattern = c("^A", "^B")
    ),
    "'pattern' must be NULL or a single non-empty character string"
  )
})

test_that("id_check rejects malformed regular expression", {

  dat <- data.frame(
    ID = "A001"
  )

  expect_error(
    id_check(
      dat,
      "ID",
      pattern = "["
    ),
    "'pattern' is not a valid regular expression"
  )
})

#==========================================================
# Unsupported identifier types
#==========================================================

test_that("id_check rejects logical identifier", {

  dat <- data.frame(
    ID = c(
      TRUE,
      FALSE
    )
  )

  expect_error(
    id_check(
      dat,
      "ID"
    ),
    "'variable' must refer to a character, factor, numeric, or integer variable"
  )
})

test_that("id_check rejects Date identifier", {

  dat <- data.frame(
    ID = as.Date(
      c(
        "2026-01-01",
        "2026-01-02"
      )
    )
  )

  expect_error(
    id_check(
      dat,
      "ID"
    ),
    "'variable' must refer to a character, factor, numeric, or integer variable"
  )
})

#==========================================================
# Invalid data
#==========================================================

test_that("id_check rejects invalid data", {

  expect_error(
    id_check(
      NULL,
      "ID"
    )
  )

  expect_error(
    id_check(
      1:5,
      "ID"
    )
  )

  expect_error(
    id_check(
      list(ID = "A001"),
      "ID"
    )
  )

  expect_error(
    id_check(
      data.frame(),
      "ID"
    )
  )
})
