library(testthat)
library(DataAudit)


test_that("summary returns correct class", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  result <- summary(report)

  expect_s3_class(
    result,
    "summary.DataAuditReport"
  )

  expect_type(
    result,
    "list"
  )
})


test_that("summary contains expected components", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  result <- summary(report)

  expect_equal(
    names(result),
    c(
      "dataset",
      "variables_with_issues",
      "duplicate_rows",
      "rules"
    )
  )
})


test_that("dataset summary contains expected fields", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  result <- summary(report)

  expect_equal(
    names(result$dataset),
    c(
      "Rows",
      "Variables",
      "VariablesWithIssues",
      "DuplicateRows",
      "TotalIssues",
      "RuleViolations",
      "OverallIssues"
    )
  )
})


test_that("summary identifies variables with issues", {

  report <- audit_data(
    data.frame(
      x = c(1, NA, 3),
      y = 1:3
    ),
    include_nzv = FALSE
  )

  result <- summary(report)

  expect_equal(
    result$variables_with_issues$Variable,
    "x"
  )
})


test_that("summary returns empty variable table when clean", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  result <- summary(report)

  expect_equal(
    nrow(result$variables_with_issues),
    0L
  )
})


test_that("summary identifies duplicate rows", {

  report <- audit_data(
    data.frame(
      x = c(
        1,
        2,
        2,
        3
      )
    ),
    include_nzv = FALSE
  )

  result <- summary(report)

  expect_equal(
    result$duplicate_rows$Row,
    c(2L, 3L)
  )
})


test_that("summary returns empty duplicate table when clean", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  result <- summary(report)

  expect_equal(
    nrow(result$duplicate_rows),
    0L
  )
})


test_that("summary returns NULL rules without custom rules", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  result <- summary(report)

  expect_null(
    result$rules
  )

  expect_equal(
    result$dataset$RuleViolations,
    0L
  )
})


test_that("summary includes custom rule results", {

  dat <- data.frame(
    ID = c(
      "A001",
      "A002",
      "A002"
    ),
    Age = c(
      5,
      40,
      -2
    )
  )

  rules <- audit_rules(
    range = list(
      Age = c(0, 30)
    ),
    unique = "ID"
  )

  report <- audit_data(
    dat,
    include_nzv = FALSE,
    rules = rules
  )

  result <- summary(report)

  expect_true(
    is.data.frame(result$rules)
  )

  expect_equal(
    names(result$rules),
    c(
      "Rule",
      "Violations"
    )
  )

  expect_equal(
    result$dataset$RuleViolations,
    report$rules$total_violations
  )
})


test_that("summary reports combined overall issues", {

  dat <- data.frame(
    Age = c(
      5,
      NA,
      40
    )
  )

  rules <- audit_rules(
    range = list(
      Age = c(0, 30)
    )
  )

  report <- audit_data(
    dat,
    include_nzv = FALSE,
    rules = rules
  )

  result <- summary(report)

  expect_equal(
    result$dataset$OverallIssues,
    result$dataset$TotalIssues +
      result$dataset$RuleViolations
  )
})


#==========================================================
# Defensive validation
#==========================================================

test_that("summary rejects object without correct class", {

  x <- list(
    overview = data.frame(),
    variables = data.frame(),
    duplicates = data.frame(),
    summary = data.frame(),
    rules = NULL
  )

  expect_error(
    summary.DataAuditReport(x),
    "Invalid 'DataAuditReport' object"
  )
})


test_that("summary rejects malformed report", {

  x <- list(
    overview = data.frame()
  )

  class(x) <- c(
    "DataAuditReport",
    "list"
  )

  expect_error(
    summary(x),
    "Invalid 'DataAuditReport' object"
  )
})


test_that("summary rejects invalid dataset summary", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  report$summary <- "invalid"

  expect_error(
    summary(report),
    "Invalid summary in 'DataAuditReport'"
  )
})


test_that("summary rejects missing dataset summary columns", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  report$summary <- data.frame(
    Wrong = 1
  )

  expect_error(
    summary(report),
    "Invalid summary in 'DataAuditReport'"
  )
})


test_that("summary rejects invalid variable summary", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  report$variables <- "invalid"

  expect_error(
    summary(report),
    "Invalid variable summary in 'DataAuditReport'"
  )
})


test_that("summary rejects variable summary without Issue", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  report$variables <- data.frame(
    Variable = "x"
  )

  expect_error(
    summary(report),
    "Invalid variable summary in 'DataAuditReport'"
  )
})


test_that("summary rejects invalid duplicate summary", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  report$duplicates <- "invalid"

  expect_error(
    summary(report),
    "Invalid duplicate summary in 'DataAuditReport'"
  )
})


test_that("summary rejects duplicate summary without Duplicate", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  report$duplicates <- data.frame(
    Row = 1:5
  )

  expect_error(
    summary(report),
    "Invalid duplicate summary in 'DataAuditReport'"
  )
})


test_that("summary rejects invalid rule result", {

  report <- audit_data(
    data.frame(
      x = 1:5
    ),
    include_nzv = FALSE
  )

  report$rules <- list(
    invalid = TRUE
  )

  expect_error(
    summary(report),
    "Invalid rule results in 'DataAuditReport'"
  )
})


test_that("summary rejects non-data-frame rule summary", {

  report <- audit_data(
    data.frame(
      Age = c(5, 40)
    ),
    include_nzv = FALSE,
    rules = audit_rules(
      range = list(
        Age = c(0, 30)
      )
    )
  )

  report$rules$summary <- "invalid"

  expect_error(
    summary(report),
    "Invalid rule summary in 'DataAuditReport'"
  )
})


test_that("summary rejects malformed rule summary", {

  report <- audit_data(
    data.frame(
      Age = c(5, 40)
    ),
    include_nzv = FALSE,
    rules = audit_rules(
      range = list(
        Age = c(0, 30)
      )
    )
  )

  report$rules$summary <- data.frame(
    Wrong = 1
  )

  expect_error(
    summary(report),
    "Invalid rule summary in 'DataAuditReport'"
  )
})
