# ============================================================================
# OdysseusCharacterizationModule — All Available Spec Combinations
# ============================================================================
#
# This script demonstrates every available combination of analysis
# specifications produced by `planAnalysis()` + `singleNodeSetting()`.
#
# Each section can be run independently. Rendered SQL is printed to the
# console for inspection.
# ============================================================================

library(OdysseusCharacterizationModule)

# Common parameters used across all examples
COHORT_ID              <- 1L
COHORT_DATABASE_SCHEMA <- "results"
COHORT_TABLE           <- "cohort"
CDM_DATABASE_SCHEMA    <- "cdm"
VOCABULARY_SCHEMA      <- "cdm"

# Shared time windows — short pre-index and post-index
windows <- defineAnalysisWindows(
  startDays = c(-30, 1),
  endDays   = c(-1, 30)
)

# Helper: render and print SQL for the first spec in a list
show_rendered_sql <- function(specs, n = 1L, max_chars = 800) {
  for (i in seq_len(min(n, length(specs)))) {
    cat(sprintf("\n-- Rendered SQL for spec %d (analysisId=%d) --\n",
                i, specs[[i]]$analysisId))
    sql <- renderSpecSql(specs[[i]])
    cat(sql, "\n")
    cat(strrep("-", 60), "\n")
  }
}


# ============================================================================
# 1. BASE FEATURES — One Domain at a Time (start type, aggregated)
# ============================================================================
# Each of the 9 supported domains enabled individually, type = "start",
# ATC disabled, aggregated = TRUE.

base_domains <- c(
  "condition_occurrence",
  "condition_era",
  "drug_exposure",
  "drug_era",
  "procedure_occurrence",
  "observation",
  "device_exposure",
  "visit_occurrence",
  "measurement"
)

for (domain in base_domains) {
  cat("\n\n--- Base feature:", domain, "(start, aggregated) ---\n")

  bf <- setNames(
    lapply(base_domains, function(d) {
      cfg <- list(include = identical(d, domain))
      # Only set type for domains that accept it
      if (d %in% c("condition_occurrence", "condition_era", "drug_era", "visit_occurrence")) {
        cfg$type <- "start"
      }
      cfg
    }),
    base_domains
  )

  plan <- planAnalysis(
    analysisWindows       = windows,
    useBaseFeatures       = bf,
    useCohortFeatures     = list(include = FALSE),
    useConceptSetFeatures = list(include = FALSE)
  )

  specs <- singleNodeSetting(
    plan                    = plan,
    cohortId                = COHORT_ID,
    cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
    cohortTable             = COHORT_TABLE,
    cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
    vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
    aggregated              = TRUE
  )

  cat("Number of specs:", length(specs), "\n")
  print(specs[[1]])
  show_rendered_sql(specs)
}


# ============================================================================
# 2. BASE FEATURES — Overlap Type (era / visit domains only)
# ============================================================================
# Domains that support overlap: condition_era, drug_era, visit_occurrence.

overlap_domains <- c("condition_era", "drug_era", "visit_occurrence")

for (domain in overlap_domains) {
  cat("\n\n--- Base feature:", domain, "(overlap, aggregated) ---\n")

  bf <- setNames(
    lapply(base_domains, function(d) {
      if (identical(d, domain)) {
        list(include = TRUE, type = "overlap")
      } else {
        list(include = FALSE)
      }
    }),
    base_domains
  )

  plan <- planAnalysis(
    analysisWindows       = windows,
    useBaseFeatures       = bf,
    useCohortFeatures     = list(include = FALSE),
    useConceptSetFeatures = list(include = FALSE)
  )

  specs <- singleNodeSetting(
    plan                    = plan,
    cohortId                = COHORT_ID,
    cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
    cohortTable             = COHORT_TABLE,
    cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
    vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
    aggregated              = TRUE
  )

  cat("Number of specs:", length(specs), "\n")
  print(specs[[1]])
  show_rendered_sql(specs)
}


# ============================================================================
# 3. BASE FEATURES — ATC Roll-Up (drug domains only)
# ============================================================================
# ATC is only applicable to drug_exposure and drug_era.
# Each ATC level (1–5) produces a separate spec per window.

atc_domains <- c("drug_exposure", "drug_era")

for (domain in atc_domains) {
  cat("\n\n--- Base feature:", domain, "(ATC levels 1-5, aggregated) ---\n")

  bf <- setNames(
    lapply(base_domains, function(d) {
      if (identical(d, domain)) {
        list(include = TRUE, type = "start", atc = TRUE, atcLevels = c(1L, 2L, 3L, 4L, 5L))
      } else {
        list(include = FALSE)
      }
    }),
    base_domains
  )

  plan <- planAnalysis(
    analysisWindows       = windows,
    useBaseFeatures       = bf,
    useCohortFeatures     = list(include = FALSE),
    useConceptSetFeatures = list(include = FALSE)
  )

  specs <- singleNodeSetting(
    plan                    = plan,
    cohortId                = COHORT_ID,
    cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
    cohortTable             = COHORT_TABLE,
    cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
    vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
    aggregated              = TRUE
  )

  cat("Number of specs:", length(specs), "(5 ATC levels x 2 windows)\n")
  for (i in seq_len(min(3, length(specs)))) {
    print(specs[[i]])
  }
  show_rendered_sql(specs)
}


# ============================================================================
# 4. BASE FEATURES — ATC with Subset of Levels
# ============================================================================
# Only ATC levels 3 and 5 for drug_exposure.

cat("\n\n--- Base feature: drug_exposure (ATC levels 3,5 only) ---\n")

bf_atc_subset <- setNames(
  lapply(base_domains, function(d) {
    if (d == "drug_exposure") {
      list(include = TRUE, type = "start", atc = TRUE, atcLevels = c(3L, 5L))
    } else {
      list(include = FALSE)
    }
  }),
  base_domains
)

plan_atc_subset <- planAnalysis(
  analysisWindows       = windows,
  useBaseFeatures       = bf_atc_subset,
  useCohortFeatures     = list(include = FALSE),
  useConceptSetFeatures = list(include = FALSE)
)

specs_atc_subset <- singleNodeSetting(
  plan                    = plan_atc_subset,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = TRUE
)

cat("Number of specs:", length(specs_atc_subset), "(2 ATC levels x 2 windows)\n")
for (s in specs_atc_subset) print(s)
show_rendered_sql(specs_atc_subset)


# ============================================================================
# 5. BASE FEATURES — Non-Aggregated (patient-level)
# ============================================================================

cat("\n\n--- Base feature: condition_occurrence (start, non-aggregated) ---\n")

plan_raw <- planAnalysis(
  analysisWindows = windows,
  useBaseFeatures = list(
    condition_occurrence = list(include = TRUE, type = "start"),
    condition_era        = list(include = FALSE),
    drug_exposure        = list(include = FALSE),
    drug_era             = list(include = FALSE),
    procedure_occurrence = list(include = FALSE),
    observation          = list(include = FALSE),
    device_exposure      = list(include = FALSE),
    visit_occurrence     = list(include = FALSE),
    measurement          = list(include = FALSE)
  ),
  useCohortFeatures     = list(include = FALSE),
  useConceptSetFeatures = list(include = FALSE)
)

specs_raw <- singleNodeSetting(
  plan                    = plan_raw,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = FALSE
)

cat("Number of specs:", length(specs_raw), "\n")
cat("Aggregated flag:", specs_raw[[1]]$aggregated, "\n")
print(specs_raw[[1]])
show_rendered_sql(specs_raw)


# ============================================================================
# 6. COHORT FEATURES — Start Type
# ============================================================================

cat("\n\n--- Cohort features (start type) ---\n")

plan_cohort_start <- planAnalysis(
  analysisWindows = windows,
  useBaseFeatures = list(
    condition_occurrence = list(include = FALSE),
    condition_era        = list(include = FALSE),
    drug_exposure        = list(include = FALSE),
    drug_era             = list(include = FALSE),
    procedure_occurrence = list(include = FALSE),
    observation          = list(include = FALSE),
    device_exposure      = list(include = FALSE),
    visit_occurrence     = list(include = FALSE),
    measurement          = list(include = FALSE)
  ),
  useCohortFeatures = list(
    include         = TRUE,
    type            = "overlap",
    cohortIds       = c(101L, 102L),
    cohortNames     = c("T2DM", "Hypertension"),
    cohortTable     = "feature_cohorts",
    covariateSchema = "results"
  ),
  useConceptSetFeatures = list(include = FALSE)
)

specs_cohort_start <- singleNodeSetting(
  plan                    = plan_cohort_start,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = TRUE
)

cat("Number of specs:", length(specs_cohort_start),
    "(2 cohorts x 2 windows)\n")
for (s in specs_cohort_start) print(s)
show_rendered_sql(specs_cohort_start)


# ============================================================================
# 7. COHORT FEATURES — Overlap Type
# ============================================================================
# Cohort covariates also support overlap logic. When type = "overlap",
# the SQL uses the dateColEnd (cohort_end_date) to check whether the
# cohort period overlaps the analysis time window, rather than just
# checking whether cohort_start_date falls inside the window.

cat("\n\n--- Cohort features (overlap type) ---\n")

plan_cohort_overlap <- planAnalysis(
  analysisWindows = windows,
  useBaseFeatures = list(
    condition_occurrence = list(include = FALSE),
    condition_era        = list(include = FALSE),
    drug_exposure        = list(include = FALSE),
    drug_era             = list(include = FALSE),
    procedure_occurrence = list(include = FALSE),
    observation          = list(include = FALSE),
    device_exposure      = list(include = FALSE),
    visit_occurrence     = list(include = FALSE),
    measurement          = list(include = FALSE)
  ),
  useCohortFeatures = list(
    include         = TRUE,
    type            = "overlap",
    cohortIds       = c(201L, 202L),
    cohortNames     = c("CKD", "Heart Failure"),
    cohortTable     = "feature_cohorts",
    covariateSchema = "results"
  ),
  useConceptSetFeatures = list(include = FALSE)
)

specs_cohort_overlap <- singleNodeSetting(
  plan                    = plan_cohort_overlap,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = TRUE
)

cat("Number of specs:", length(specs_cohort_overlap),
    "(2 cohorts x 2 windows)\n")
for (s in specs_cohort_overlap) {
  print(s)
  cat("  overlap flag:", s$overlap, "\n")
  cat("  dateColEnd:  ", s$dateColEnd, "\n")
  cat("  personIdCol: ", s$personIdCol, "\n\n")
}

show_rendered_sql(specs_cohort_overlap)


# ============================================================================
# 8. CONCEPT SET FEATURES — Binary Type
# ============================================================================

cat("\n\n--- Concept set features (binary, single table) ---\n")

plan_cs_binary <- planAnalysis(
  analysisWindows = windows,
  useBaseFeatures = list(
    condition_occurrence = list(include = FALSE),
    condition_era        = list(include = FALSE),
    drug_exposure        = list(include = FALSE),
    drug_era             = list(include = FALSE),
    procedure_occurrence = list(include = FALSE),
    observation          = list(include = FALSE),
    device_exposure      = list(include = FALSE),
    visit_occurrence     = list(include = FALSE),
    measurement          = list(include = FALSE)
  ),
  useCohortFeatures = list(include = FALSE),
  useConceptSetFeatures = list(
    include = TRUE,
    type    = "binary",
    conceptSets = list(
      diabetes = list(
        items = list(
          list(concept = list(CONCEPT_ID = 201820L), includeDescendants = TRUE),
          list(concept = list(CONCEPT_ID = 443238L))
        ),
        tables = c("condition_occurrence")
      )
    )
  )
)

specs_cs_binary <- singleNodeSetting(
  plan                    = plan_cs_binary,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = F
)

cat("Number of specs:", length(specs_cs_binary), "\n")
for (s in specs_cs_binary) print(s)
show_rendered_sql(specs_cs_binary)


# ============================================================================
# 9. CONCEPT SET FEATURES — Counts Type
# ============================================================================

cat("\n\n--- Concept set features (counts, single table) ---\n")

plan_cs_counts <- planAnalysis(
  analysisWindows = windows,
  useBaseFeatures = list(
    condition_occurrence = list(include = FALSE),
    condition_era        = list(include = FALSE),
    drug_exposure        = list(include = FALSE),
    drug_era             = list(include = FALSE),
    procedure_occurrence = list(include = FALSE),
    observation          = list(include = FALSE),
    device_exposure      = list(include = FALSE),
    visit_occurrence     = list(include = FALSE),
    measurement          = list(include = FALSE)
  ),
  useCohortFeatures = list(include = FALSE),
  useConceptSetFeatures = list(
    include = TRUE,
    type    = "counts",
    conceptSets = list(
      lab_tests = list(
        items = list(
          list(concept = list(CONCEPT_ID = 3004249L), includeDescendants = TRUE)
        ),
        tables = c("measurement")
      )
    )
  )
)

specs_cs_counts <- singleNodeSetting(
  plan                    = plan_cs_counts,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = TRUE
)

cat("Number of specs:", length(specs_cs_counts), "\n")
for (s in specs_cs_counts) print(s)
show_rendered_sql(specs_cs_counts)


# ============================================================================
# 10. CONCEPT SET FEATURES — Multiple Tables
# ============================================================================
# A concept set that searches across condition_occurrence AND drug_exposure.

cat("\n\n--- Concept set features (binary, multiple tables) ---\n")

plan_cs_multi <- planAnalysis(
  analysisWindows = windows,
  useBaseFeatures = list(
    condition_occurrence = list(include = FALSE),
    condition_era        = list(include = FALSE),
    drug_exposure        = list(include = FALSE),
    drug_era             = list(include = FALSE),
    procedure_occurrence = list(include = FALSE),
    observation          = list(include = FALSE),
    device_exposure      = list(include = FALSE),
    visit_occurrence     = list(include = FALSE),
    measurement          = list(include = FALSE)
  ),
  useCohortFeatures = list(include = FALSE),
  useConceptSetFeatures = list(
    include = TRUE,
    type    = "binary",
    conceptSets = list(
      aspirin = list(
        items = list(
          list(concept = list(CONCEPT_ID = 1112807L), includeDescendants = TRUE)
        ),
        tables = c("condition_occurrence", "drug_exposure")
      )
    )
  )
)

specs_cs_multi <- singleNodeSetting(
  plan                    = plan_cs_multi,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = TRUE
)

cat("Number of specs:", length(specs_cs_multi),
    "(1 concept set x 2 tables x 2 windows)\n")
for (s in specs_cs_multi) print(s)
show_rendered_sql(specs_cs_multi, n = 2L)  # show both tables


# ============================================================================
# 11. CONCEPT SET FEATURES — Multiple Concept Sets
# ============================================================================

cat("\n\n--- Concept set features (multiple concept sets) ---\n")

plan_cs_multi_sets <- planAnalysis(
  analysisWindows = windows,
  useBaseFeatures = list(
    condition_occurrence = list(include = FALSE),
    condition_era        = list(include = FALSE),
    drug_exposure        = list(include = FALSE),
    drug_era             = list(include = FALSE),
    procedure_occurrence = list(include = FALSE),
    observation          = list(include = FALSE),
    device_exposure      = list(include = FALSE),
    visit_occurrence     = list(include = FALSE),
    measurement          = list(include = FALSE)
  ),
  useCohortFeatures = list(include = FALSE),
  useConceptSetFeatures = list(
    include = TRUE,
    type    = "binary",
    conceptSets = list(
      diabetes = list(
        items  = list(list(concept = list(CONCEPT_ID = 201820L), includeDescendants = TRUE)),
        tables = c("condition_occurrence")
      ),
      hypertension = list(
        items  = list(list(concept = list(CONCEPT_ID = 316866L), includeDescendants = TRUE)),
        tables = c("condition_occurrence")
      ),
      metformin = list(
        items  = list(list(concept = list(CONCEPT_ID = 1503297L), includeDescendants = TRUE)),
        tables = c("drug_exposure")
      )
    )
  )
)

specs_cs_multi_sets <- singleNodeSetting(
  plan                    = plan_cs_multi_sets,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = TRUE
)

cat("Number of specs:", length(specs_cs_multi_sets), "\n")
print(specs_cs_multi_sets)
show_rendered_sql(specs_cs_multi_sets, n = 3L)  # one per concept set


# ============================================================================
# 12. COMBINED — Base + Cohort + Concept Set Features Together
# ============================================================================

cat("\n\n--- Full combination: base + cohort + concept set ---\n")

plan_full <- planAnalysis(
  analysisWindows = windows,
  useBaseFeatures = list(
    condition_occurrence = list(include = TRUE, type = "start"),
    condition_era        = list(include = TRUE, type = "overlap"),
    drug_exposure        = list(include = TRUE, atc = TRUE, atcLevels = c(3L, 5L)),
    drug_era             = list(include = FALSE),
    procedure_occurrence = list(include = TRUE),
    observation          = list(include = FALSE),
    device_exposure      = list(include = FALSE),
    visit_occurrence     = list(include = TRUE, type = "start"),
    measurement          = list(include = TRUE)
  ),
  useCohortFeatures = list(
    include         = TRUE,
    type            = "start",
    cohortIds       = c(101L, 102L, 103L),
    cohortNames     = c("T2DM", "Hypertension", "CKD"),
    cohortTable     = "feature_cohorts",
    covariateSchema = "results"
  ),
  useConceptSetFeatures = list(
    include = TRUE,
    type    = "binary",
    conceptSets = list(
      diabetes = list(
        items  = list(list(concept = list(CONCEPT_ID = 201820L), includeDescendants = TRUE)),
        tables = c("condition_occurrence")
      ),
      metformin = list(
        items  = list(list(concept = list(CONCEPT_ID = 1503297L), includeDescendants = TRUE)),
        tables = c("drug_exposure", "drug_era")
      )
    )
  )
)

specs_full <- singleNodeSetting(
  plan                    = plan_full,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = TRUE
)

print(specs_full)
cat("\nTotal specs generated:", length(specs_full), "\n")
# Show one rendered SQL per source type (base, cohort, conceptSet)
for (src in c("base", "cohort", "conceptSet")) {
  idx <- which(vapply(specs_full, function(s) s$source, character(1)) == src)[1]
  if (!is.na(idx)) {
    cat(sprintf("\n-- Rendered SQL for first '%s' spec --\n", src))
    show_rendered_sql(specs_full[idx])
  }
}


# ============================================================================
# 13. RENDER SQL — Different Dialects
# ============================================================================
# Take one spec and render for multiple target platforms.

cat("\n\n--- SQL dialect rendering ---\n")

# Build a minimal spec for demonstration
plan_minimal <- planAnalysis(
  analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1),
  useBaseFeatures = list(
    condition_occurrence = list(include = TRUE, type = "start"),
    condition_era        = list(include = FALSE),
    drug_exposure        = list(include = FALSE),
    drug_era             = list(include = FALSE),
    procedure_occurrence = list(include = FALSE),
    observation          = list(include = FALSE),
    device_exposure      = list(include = FALSE),
    visit_occurrence     = list(include = FALSE),
    measurement          = list(include = FALSE)
  ),
  useCohortFeatures     = list(include = FALSE),
  useConceptSetFeatures = list(include = FALSE)
)

specs_min <- singleNodeSetting(
  plan                    = plan_minimal,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = TRUE
)

one_spec <- specs_min[[1]]

dialects <- c("sql server", "postgresql", "redshift", "oracle", "spark")

for (dialect in dialects) {
  cat("\n--- Dialect:", dialect, "---\n")
  rendered <- tryCatch(
    renderSpecSql(one_spec, targetDialect = dialect),
    error = function(e) paste("Error:", conditionMessage(e))
  )
  cat(substr(rendered, 1, 300), "\n...\n")
}


# ============================================================================
# 14. RENDER ALL — Batch Rendering
# ============================================================================

cat("\n\n--- Batch rendering with renderAllSpecSql ---\n")

all_sql <- renderAllSpecSql(specs_min)
cat("Number of SQL statements:", length(all_sql), "\n")
cat("Analysis IDs:", paste(names(all_sql), collapse = ", "), "\n")
cat("First SQL preview:\n")
cat(substr(all_sql[[1]], 1, 300), "\n...\n")


# ============================================================================
# 15. MULTIPLE TIME WINDOWS
# ============================================================================
# Demonstrate how the number of windows multiplies spec count.

cat("\n\n--- Multiple time windows (8 windows) ---\n")

windows_many <- defineAnalysisWindows(
  startDays = c(-365, -180, -30, 0, 1, 30, 180, 365),
  endDays   = c(-1,   -1,  -1, 0, 30, 180, 365, 700)
)

plan_many_windows <- planAnalysis(
  analysisWindows = windows_many,
  useBaseFeatures = list(
    condition_occurrence = list(include = TRUE, type = "start"),
    condition_era        = list(include = FALSE),
    drug_exposure        = list(include = TRUE, atc = TRUE, atcLevels = c(1L, 3L, 5L)),
    drug_era             = list(include = FALSE),
    procedure_occurrence = list(include = FALSE),
    observation          = list(include = FALSE),
    device_exposure      = list(include = FALSE),
    visit_occurrence     = list(include = FALSE),
    measurement          = list(include = FALSE)
  ),
  useCohortFeatures     = list(include = FALSE),
  useConceptSetFeatures = list(include = FALSE)
)

specs_many <- singleNodeSetting(
  plan                    = plan_many_windows,
  cohortId                = COHORT_ID,
  cohortDatabaseSchema    = COHORT_DATABASE_SCHEMA,
  cohortTable             = COHORT_TABLE,
  cdmDatabaseSchema       = CDM_DATABASE_SCHEMA,
  vocabularyDatabaseSchema = VOCABULARY_SCHEMA,
  aggregated              = TRUE
)

print(specs_many)
cat("\nExpected: condition_occurrence (1 domain x 8 windows = 8) +",
    "drug_exposure ATC (3 levels x 8 windows = 24) = 32 total\n")
cat("Actual:", length(specs_many), "\n")


# ============================================================================
# SUMMARY TABLE
# ============================================================================

cat("\n\n")
cat("============================================================\n")
cat("  SPEC COMBINATION SUMMARY\n")
cat("============================================================\n")
cat(sprintf("  %-45s  %s\n", "Combination", "Specs"))
cat(sprintf("  %-45s  %s\n", strrep("-", 45), strrep("-", 5)))
cat(sprintf("  %-45s  %d\n", "1.  Base domain (start, aggregated) x9",       9 * 2))
cat(sprintf("  %-45s  %d\n", "2.  Base domain (overlap) x3",                 3 * 2))
cat(sprintf("  %-45s  %d\n", "3.  Drug + ATC all levels x2",                 2 * 5 * 2))
cat(sprintf("  %-45s  %d\n", "4.  Drug + ATC subset (3,5)",                  2 * 2))
cat(sprintf("  %-45s  %d\n", "5.  Base domain (non-aggregated)",             1 * 2))
cat(sprintf("  %-45s  %d\n", "6.  Cohort features (start)",                  2 * 2))
cat(sprintf("  %-45s  %d\n", "7.  Cohort features (overlap)",                2 * 2))
cat(sprintf("  %-45s  %d\n", "8.  Concept set (binary, 1 table)",            1 * 2))
cat(sprintf("  %-45s  %d\n", "9.  Concept set (counts, 1 table)",            1 * 2))
cat(sprintf("  %-45s  %d\n", "10. Concept set (binary, 2 tables)",           2 * 2))
cat(sprintf("  %-45s  %d\n", "11. Concept set (3 sets, various tables)",     3 * 2))
cat(sprintf("  %-45s  %d\n", "12. Full combination (base+cohort+cs)", length(specs_full)))
cat(sprintf("  %-45s  %d\n", "15. 8 windows x (cond + drug ATC(1,3,5))", length(specs_many)))
cat("============================================================\n")
