#==========================================================
# Data Audit Score
#==========================================================

#' Calculate a Data Quality Score
#'
#' Calculates a standardized data-quality score from a
#' \code{DataAuditReport} produced by \code{\link{audit_data}}.
#'
#' @param x An object of class \code{DataAuditReport}.
#'
#' @return An object of class \code{DataAuditScore}.
#'
#' @details
#' The score ranges from 0 to 100, where higher values
#' indicate better data quality.
#'
#' The score is based on automatic audit issues and custom
#' rule violations relative to the number of observations
#' and variables in the audited dataset.
#'
#' @examples
#' dat <- data.frame(
#'   ID = c(1, 2, 2, 4),
#'   Value = c(10, NA, Inf, 20)
#' )
#'
#' report <- audit_data(dat)
#' audit_score(report)
#'
#' @export

audit_score <- function(x) {

  #---------------------------------------------
  # Validate object
  #---------------------------------------------
  if (!inherits(x, "DataAuditReport")) {

    stop(
      "'x' must be a DataAuditReport object.",
      call. = FALSE
    )
  }

  required_components <- c(
    "variables",
    "summary"
  )

  if (
    !all(
      required_components %in%
      names(x)
    )
  ) {

    stop(
      "Invalid 'DataAuditReport' object.",
      call. = FALSE
    )
  }

  if (
    !is.data.frame(x$summary) ||
    nrow(x$summary) != 1L
  ) {

    stop(
      "Invalid summary in 'DataAuditReport'.",
      call. = FALSE
    )
  }

  required_summary <- c(
    "Rows",
    "Variables",
    "TotalIssues",
    "RuleViolations",
    "OverallIssues"
  )

  if (
    !all(
      required_summary %in%
      names(x$summary)
    )
  ) {

    stop(
      "Invalid summary in 'DataAuditReport'.",
      call. = FALSE
    )
  }

  #---------------------------------------------
  # Extract values
  #---------------------------------------------
  n_rows <- x$summary$Rows[[1L]]
  n_variables <- x$summary$Variables[[1L]]
  automatic_issues <-
    x$summary$TotalIssues[[1L]]
  rule_violations <-
    x$summary$RuleViolations[[1L]]
  overall_issues <-
    x$summary$OverallIssues[[1L]]

  #---------------------------------------------
  # Validate values
  #---------------------------------------------
  values <- c(
    n_rows,
    n_variables,
    automatic_issues,
    rule_violations,
    overall_issues
  )

  if (
    any(!is.numeric(values)) ||
    any(is.na(values)) ||
    any(!is.finite(values)) ||
    n_rows <= 0 ||
    n_variables <= 0 ||
    automatic_issues < 0 ||
    rule_violations < 0 ||
    overall_issues < 0
  ) {

    stop(
      "Invalid values in DataAudit summary.",
      call. = FALSE
    )
  }

  #---------------------------------------------
  # Number of data cells
  #---------------------------------------------
  total_cells <-
    n_rows * n_variables

  #---------------------------------------------
  # Issue burden
  #
  # log1p prevents very large numbers of
  # violations from producing unstable scores.
  #---------------------------------------------
  burden <-
    overall_issues / total_cells

  #---------------------------------------------
  # Convert burden to 0-100 score
  #---------------------------------------------
  score <-
    100 / (1 + burden)

  score <- max(
    0,
    min(
      100,
      score
    )
  )

  #---------------------------------------------
  # Quality category
  #---------------------------------------------
  quality <- if (score >= 95) {

    "Excellent"

  } else if (score >= 85) {

    "Good"

  } else if (score >= 70) {

    "Moderate"

  } else if (score >= 50) {

    "Poor"

  } else {

    "Critical"
  }

  #---------------------------------------------
  # Construct result
  #---------------------------------------------
  result <- list(
    score = as.numeric(score),
    quality = quality,
    automatic_issues =
      as.integer(automatic_issues),
    rule_violations =
      as.integer(rule_violations),
    overall_issues =
      as.integer(overall_issues),
    rows = as.integer(n_rows),
    variables = as.integer(n_variables),
    total_cells =
      as.numeric(total_cells)
  )

  class(result) <- c(
    "DataAuditScore",
    "list"
  )

  result
}
