# Container usage:
# Rscript /srv/shiny-server/NAS_deploy/verify_app.R /srv/shiny-server/EsoDev_Alltime
# Windows usage (RStudio): source('.../NAS_deploy/verify_app.R')
.libPaths(c('~/SeuratV4', .libPaths()))
verify_esodev_app <- function(app, prefix = 'RNA') {
  required <- c('shiny', 'shinyhelper', 'data.table', 'Matrix', 'DT',
                'magrittr', 'ggplot2', 'ggrepel', 'hdf5r', 'ggdendro',
                'gridExtra', 'ggpubr')
  missing <- required[!vapply(required, requireNamespace, logical(1), quietly = TRUE)]
  if (length(missing)) stop('Missing runtime packages: ', paste(missing, collapse = ', '))
  files <- c('server.R', 'ui.R', 'shinyFunc.R',
             paste0(prefix, c('conf.rds', 'def.rds', 'dimr.rds', 'gene.rds', 'meta.rds')),
             paste0(prefix, 'assay_', c('RNA', 'GSVA', 'Pro'), '.h5'))
  if (!all(file.exists(file.path(app, files)))) {
    stop('Missing app files: ', paste(files[!file.exists(file.path(app, files))], collapse = ', '))
  }
  for (f in files) {
    if (file.access(file.path(app, f), 4L) != 0L) stop('File is not readable: ', f)
  }
  for (f in c('server.R', 'ui.R', 'shinyFunc.R')) invisible(parse(file.path(app, f)))
  meta <- readRDS(file.path(app, paste0(prefix, 'meta.rds')))
  genes <- readRDS(file.path(app, paste0(prefix, 'gene.rds')))
  def <- readRDS(file.path(app, paste0(prefix, 'def.rds')))
  dimr <- readRDS(file.path(app, paste0(prefix, 'dimr.rds')))
  stopifnot(all(c('RNA', 'GSVA', 'Pro') %in% def$assay),
            !anyDuplicated(meta$cellID), all(c('celltype7', 'time') %in% names(meta)))
  for (nm in names(dimr)) {
    stopifnot(identical(rownames(dimr[[nm]]), as.character(meta$cellID)))
  }
  for (assay in c('RNA', 'GSVA', 'Pro')) {
    f <- hdf5r::H5File$new(file.path(app, paste0(prefix, 'assay_', assay, '.h5')), mode = 'r')
    tryCatch({
      d <- f[['grp/data']]
      stopifnot(identical(as.integer(d$dims), c(length(genes[[assay]]), nrow(meta))))
      # Read from both ends to catch a missing/truncated data file after copying.
      sample <- d[c(1L, d$dims[1]), c(1L, d$dims[2]), drop = FALSE]
      stopifnot(all(is.finite(sample)))
      stopifnot(all(def$gene1[[assay]] %in% names(genes[[assay]])))
      cat(assay, ': ', d$dims[1], ' features x ', d$dims[2], ' cells\n', sep = '')
    }, finally = f$close_all())
  }
  bytes <- sum(file.info(file.path(app, files))$size)
  cat('Application size:', round(bytes / 1e9, 2), 'GB (', round(bytes / 1024^3, 2), 'GiB)\n')
  cat('App assets, barcodes, UMAP and runtime packages passed verification.\n')
  invisible(list(cells = nrow(meta), bytes = bytes, files = files))
}
if (sys.nframe() == 0L) {
  args <- commandArgs(trailingOnly = TRUE)
  if (length(args) != 1L) stop('Usage: Rscript verify_app.R /path/to/app')
  verify_esodev_app(args[1])
}
