#' Generate a Summary of the data and metadata in the s2dv_cube object
#'
#'This function prints the summary of the data and metadata of an object of class \code{s2dv_cube},
#'loaded using \code{CST_Start} or \code{SUNSET}.
#'   
#' @author Theertha Kariyathan, \email{theertha.kariyathan@bsc.es}
#'
#' @param data_cube An \code{s2dv_cube} object containing:
#'   - `data`: N-dimensional array with named dimensions
#'   - `dims`: Dimensions, including `var` (variables).
#'   - `attrs`: Attributes such as `VarName` and `Metadata`.
#'   - `coords`: Named list with coordinates of dimensions.
#' @param show_NA Logical. If \code{TRUE}, details of NA values in the loaded object will be displayed in the output.
#' @param loaded_files Logical. If \code{TRUE}, the names of the loaded files will be displayed.
#'   
#' @return A printed summary of the data and metadata of the \code{s2dv_cube} object, including:
#'   - months: Months that have been loaded.
#'   - range: Range of the dates that have been loaded.
#'   - dimensions: Object dimensions.
#'   - Statistical summary of the data in data_cube: Basic statistical summary of the data.
#'   - Variable: Variables that have been loaded, along with their units (units:)
#'   - NA-Indices per Dimension: Index with NA values per dimension
#'   - Number of NAs in NA-Indices per Dimensions: Number of NAs, in the Indices with NA values per dimension  
#'   - Loaded files: Successfully loaded Files
#'   
#' @details The function uses the data and metadata from the loaded \code{s2dv_cube} object to generate a summary of the object.
#' The summary includes the return parameters mentioned above.
#' The \code{show_NA} and \code{loaded_files} parameters allow the user to choose whether to display:
#' - Details of NA values in the object (if \code{show_NA = TRUE}).
#' - Information about successfully loaded files (if \code{loaded_files = TRUE}), allows users to verify that the desired files were loaded.
#' 
#' @examples
#' CST_summary(lonlat_prec_st)
#' 
#' # Example s2dv cube paths
#' repos <- "/esarchive/exp/ecmwf/system5_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc"
#' repos2 <- "/esarchive/exp/ecmwf/system4_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc"
#'
#' # Create data cube
#' data_cube <- CST_Start(dat = list(
#'                 list(name = 'system4_m1', path = repos2),
#'                 list(name = 'system5_m1', path = repos)),
#'                 var = c('tas', 'sfcWind'),
#'                 sdate = '20170101',
#'                 ensemble = indices(1),
#'                 time = indices(1),
#'                 lat = indices(1:5),
#'                 lon = indices(1:5),
#'                 synonims = list(lat = c('lat', 'latitude'),
#'                                 lon = c('lon', 'longitude')),
#'                 return_vars = list(time = 'sdate',
#'                                    longitude = 'dat',
#'                                    latitude = 'dat'),
#'                 metadata_dims = c('dat', 'var'),
#'                 retrieve = TRUE)
#'
#' # Generate summary
#' CST_summary(data_cube)
#'
#' @seealso \link[CSTools]{CST_start} or \link[SUNSET] for creating an s2dv cube object.
#' @import startR 
#' @export
CST_summary <- function(data_cube,loaded_files = TRUE, show_NA = TRUE) {
  # Get name, leadtime months and date range
  object_name <- deparse(substitute(data_cube))
  
  date_format <- "%b %d %Y"
  months <- unique(format(as.Date(data_cube$attrs$Dates), format = '%B'))
  months <- paste(as.character(months), collapse=", ")
  sdate_min <- format(min(as.Date(data_cube$attrs$Dates), na.rm = TRUE),
                      format = date_format)
  sdate_max <- format(max(as.Date(data_cube$attrs$Dates), na.rm = TRUE),
                      format = date_format)
  # Log the summary
  cat("DATA SUMMARY:\n")
  
  cat(paste(object_name, "months:", months),"\n")
  cat(paste(object_name, "range:", sdate_min, "to", sdate_max),"\n")
  cat(paste(object_name, "dimensions:"),"\n")
  
  # Use capture.output() and for loop to display results neatly
  output_string <- capture.output(dim(data_cube$data))
  for (i in output_string) {
    cat(i,"\n")
  }
  
  # Print statistical summary of the data for every variable
  cat(paste("Statistical summary of the data in ", object_name, ":"),"\n")
  if(any(names(data_cube$dims) == "var")){
  for (var_index in 1:data_cube$dims[['var']]) {
    variable_name <- data_cube$attrs$Variable$varName[var_index]
    variable_units <- data_cube$attrs$Variable$metadata[[variable_name]]$units
    cat(paste("Variable: ", variable_name,
                " (units: ", variable_units, ")"),"\n")
    output_string <- capture.output(summary(Subset(data_cube$data,
                                                   along = 'var',
                                                   indices = list(var_index))))
    for (i in output_string) {
      cat(i,"\n")
    }
  }
  }
  # Number of NAs per time dimension and latitude/longitude dimensions
  
  list_na <- lapply(seq_along(dim(data_cube$data)), function(dim) {
    apply(data_cube$data, dim, function(x) sum(is.na(x)))
  })
  
  # Identify dimensions with NAs
  na_list <- sapply(list_na, function(x) which(x != 0) %>% paste(collapse = ",")) %>% unlist()
  names(na_list) <- names(dim(data_cube$data))
  
  # Count the number of NAs per identified dimension
  num_nas <- sapply(list_na, function(x) x[which(x != 0)] %>% paste(collapse = ",")) %>% unlist()
  names(num_nas) <- names(dim(data_cube$data))
  
  # Generate output strings
  output_na_list <- paste(names(na_list), na_list, sep = ": ", collapse = " ")
  output_num_nas <- paste(names(num_nas), num_nas, sep = ": ", collapse = " ")
  
  if(show_NA == TRUE){
  cat("NA-Indices per Dimension\n")
  cat(output_na_list,"\n")
  
  cat("Number of NAs in NA-Indices per Dimensions\n") 
  cat(output_num_nas,"\n") 
  }
  # Loaded files
  if(loaded_files == TRUE){
  all_files <- lapply(data_cube$attrs$source_files, unlist) %>% unlist()
  loaded_files <- all_files[!is.na(all_files)]
  cat("Loaded files:\n")
  cat(paste(loaded_files, collapse = "\n"), "\n")
  }
  cat("---------------------------------------------","\n")
  invisible(gc())
}

