#' Population-level diagnostics
#'
#' @description
#' PhenotypeR diagnostics on the cohort of input with relation to a denomination
#' population. Diagnostics include:
#'
#' * Incidence
#' * Period Prevalence
#'
#' @inheritParams cohortDoc
#' @param cohortId Specific cohort definition ID for which to run population
#' diagnostics.
#' @param incidence Whether to run `IncidencePrevalence::estimateIncidence()` (TRUE)
#'        or not (FALSE).
#' @param periodPrevalence Whether to run `IncidencePrevalence::estimatePeriodPrevalence()` (TRUE)
#'        or not (FALSE).
#' @inheritParams populationSampleDoc
#'
#' @return A summarised result
#' @export
#'
#' @examples
#' \donttest{
#' library(omock)
#' library(CohortConstructor)
#' library(PhenotypeR)
#' library(CDMConnector)
#'
#' cdm <- mockCdmFromDataset(source = "duckdb")
#' cdm$warfarin <- conceptCohort(cdm,
#'                               conceptSet =  list(warfarin = c(1310149L,
#'                                                               40163554L)),
#'                               name = "warfarin")
#'
#' result <- cdm$warfarin |>
#'   populationDiagnostics(populationSample = 100000)
#'
#' cdmDisconnect(cdm = cdm)
#' }
populationDiagnostics <- function(cohort,
                                  cohortId = NULL,
                                  incidence = TRUE,
                                  periodPrevalence = TRUE,
                                  populationSample = 100000,
                                  populationDateRange = as.Date(c(NA, NA))) {

  cohort <- omopgenerics::validateCohortArgument(cohort = cohort)
  cohortId <- omopgenerics::validateCohortIdArgument(cohortId = cohortId,
                                                     cohort = cohort)
  checksPopulationDiagnostics(populationSample, populationDateRange)
  omopgenerics::assertLogical(incidence, length = 1)
  omopgenerics::assertLogical(periodPrevalence, length = 1)

  cdm <- omopgenerics::cdmReference(cohort)
  cohortName <- omopgenerics::tableName(cohort)

  if (!is.null(getOption("omopgenerics.logFile"))) {
    omopgenerics::logMessage("Population diagnosics - denominator cohort")
  }
  denominatorTable <- omopgenerics::uniqueTableName()

  # add population sampling
  if(!is.null(populationSample)){
    if (!is.null(getOption("omopgenerics.logFile"))) {
      omopgenerics::logMessage(paste0("Population diagnosics - sampling person table to ", populationSample, " people"))
    }
    if(is.na(populationDateRange[[1]]) && is.na(populationDateRange[[2]])){
      cdm$person <- cdm$person |>
        dplyr::slice_sample(n = populationSample)
    } else {
      # sample within date range
      if(!is.na(populationDateRange[[1]]) & is.na(populationDateRange[[2]])){
        cdm$person <- cdm$person |>
          dplyr::inner_join(cdm$observation_period|>
                              dplyr::filter(.data$observation_period_start_date >=
                                              !!populationDateRange[[1]]) |>
                              dplyr::select("person_id") |>
                              dplyr::distinct(),
                            by = "person_id") |>
          dplyr::slice_sample(n = populationSample)
      } else if(is.na(populationDateRange[[1]]) & !is.na(populationDateRange[[2]])){
        cdm$person <- cdm$person |>
          dplyr::inner_join(cdm$observation_period|>
                              dplyr::filter(.data$observation_period_start_date <=
                                              !!populationDateRange[[2]]) |>
                              dplyr::select("person_id") |>
                              dplyr::distinct(),
                            by = "person_id") |>
          dplyr::slice_sample(n = populationSample)
      } else {
        cdm$person <- cdm$person |>
          dplyr::inner_join(cdm$observation_period|>
                              dplyr::filter(.data$observation_period_start_date >=
                                              !!populationDateRange[[1]],
                                            .data$observation_period_start_date <=
                                              !!populationDateRange[[2]]) |>
                              dplyr::select("person_id") |>
                              dplyr::distinct(),
                            by = "person_id") |>
          dplyr::slice_sample(n = populationSample)
      }
    }
    cdm$person <- cdm$person |>
      dplyr::compute(temporary = TRUE)
  }

  cdm <- IncidencePrevalence::generateDenominatorCohortSet(
    cdm = cdm,
    name = denominatorTable,
    ageGroup = list(c(0, 150),
                    c(0, 17),
                    c(18, 64),
                    c(65, 150)),
    sex = c("Both", "Male", "Female"),
    daysPriorObservation = c(0, 365),
    requirementInteractions = FALSE,
    cohortDateRange = populationDateRange
  )

  results <- list()

  if(isTRUE(incidence)) {
    if (!is.null(getOption("omopgenerics.logFile"))) {
      omopgenerics::logMessage("Population diagnosics - incidence")
    }
    results[["incidence"]] <- IncidencePrevalence::estimateIncidence(
      cdm = cdm,
      denominatorTable = denominatorTable,
      outcomeTable = cohortName,
      outcomeCohortId = cohortId,
      interval = c("years", "overall"),
      repeatedEvents = FALSE,
      outcomeWashout = Inf,
      completeDatabaseIntervals = FALSE)
  }

  if(isTRUE(periodPrevalence)) {
    if (!is.null(getOption("omopgenerics.logFile"))) {
      omopgenerics::logMessage("Population diagnosics - prevalence")
    }

    results[["prevalence"]] <- IncidencePrevalence::estimatePeriodPrevalence(
      cdm = cdm,
      denominatorTable = denominatorTable,
      outcomeTable = cohortName,
      outcomeCohortId = cohortId,
      interval = c("years", "overall"),
      completeDatabaseIntervals = TRUE,
      fullContribution = FALSE)
  }

    results <- results |>
      vctrs::list_drop_empty() |>
      omopgenerics::bind()

  newSettings <- results |>
    omopgenerics::settings() |>
    dplyr::mutate("phenotyper_version" = as.character(utils::packageVersion(pkg = "PhenotypeR")),
                  "diagnostic" = "populationDiagnostics",
                  "populationDateStart" = populationDateRange[1],
                  "populationDateEnd"   = populationDateRange[2],
                  "populationSample"    = populationSample)

  results <- results |>
    omopgenerics::newSummarisedResult(settings = newSettings)

  return(results)
}

checksPopulationDiagnostics <- function(populationSample, populationDateRange, call = parent.frame()){
  omopgenerics::assertNumeric(populationSample, integerish = TRUE, min = 1, null = TRUE, length = 1, call = call)
  omopgenerics::assertDate(populationDateRange, na = TRUE, length = 2, call = call)
}

