source("modules/Saving/R/get_dir.R")
source("modules/Saving/R/get_filename.R")
source("modules/Saving/R/Utils.R")
source("modules/Saving/R/save_forecast.R")
source("modules/Saving/R/save_observations.R")
source("modules/Saving/R/save_metrics.R")
source("modules/Saving/R/save_probabilities.R")
source("modules/Saving/R/save_percentiles.R")
source("modules/Saving/R/get_times.R")
source("modules/Saving/R/get_latlon.R")
source("modules/Saving/R/get_global_attributes.R")
source("modules/Saving/R/drop_dims.R")
## TODO: Remove when packages are released
source("modules/Saving/R/tmp/ArrayToNc.R")
source("modules/Saving/R/tmp/CST_SaveExp.R")



Saving <- function(recipe, data, module, metrics = NULL, agg = "global") {

  original_output_dir <- recipe$Run$output_dir
  recipe$Run$output_dir <- file.path(recipe$Run$output_dir, "outputs", module)

  # Make categories rounded number to use as names:
  categories <- recipe$Analysis$Workflow$Probabilities$percentiles
  categories <- lapply(categories, function (x) {
                       sapply(x, function(y) {
                              round(eval(parse(text = y)), 2)})})

  # 1. Save percentiles
  limits <- list()
  ## TODO: Review if
  if (recipe$Analysis$Workflow$Probabilities$save == 'all') {
    for (ps in 1:length(categories)) {
      limits_ps <- .drop_dims(data$cat_lims$obs[[ps]])
      for (l in 1:dim(data$cat_lims$obs[[ps]])['bin']) {
        limits_subset <- ClimProjDiags::Subset(x = limits_ps,
                                               along = "bin",
                                               indices = l,
                                               drop = "selected")
        limits <- append(limits, list(limits_subset))
        names(limits)[length(limits)] <-
                paste0("p_", as.character(categories[[ps]][l]*100))
      }
    }
    info(recipe$Run$logger,
         "SAVING OBSERVED CATEGORY LIMITS")
    save_percentiles(recipe = recipe, percentiles = limits,
                     data_cube = data$obs,
                     agg = agg, outdir = NULL)
  }
  
  # 2. Save probabilities
  probs_hcst <- list()
  probs_fcst <- list()
  probs_obs <- list()
  all_names <- NULL

  # Convert arrays to named list of lists
  for (ps in 1:length(categories)) {
    for (perc in 1:(length(categories[[ps]]) + 1)) {
      if (perc == 1) {
        name_elem <- paste0("below_", categories[[ps]][perc]*100)
      } else if (perc == length(categories[[ps]]) + 1) {
        name_elem <- paste0("above_", categories[[ps]][perc-1]*100)
      } else {
        name_elem <- paste0("from_", categories[[ps]][perc-1]*100,
                            "_to_", categories[[ps]][perc]*100)
      }
      probs_hcst <- append(probs_hcst,
                           list(Subset(data$probs$hcst[[ps]],
                                       along = 'bin',
                                       indices = perc,
                                       drop = 'selected')))
      probs_obs <- append(probs_obs,
                          list(Subset(data$probs$obs[[ps]],
                                      along = 'bin',
                                      indices = perc,
                                      drop = 'selected')))
      if (!is.null(data$fcst)) {
        probs_fcst <- append(probs_fcst,
                             list(Subset(data$probs$fcst[[ps]],
                                         along = 'bin',
                                         indices = perc,
                                         drop = 'selected')))
      }
      all_names <- c(all_names, name_elem)
    }
  }
  names(probs_hcst) <- all_names
  probs_hcst <- lapply(probs_hcst, .drop_dims)
  names(probs_obs) <- all_names
  probs_obs <- lapply(probs_obs, .drop_dims)
  if (!is.null(data$fcst)) {
    names(probs_fcst) <- all_names
    probs_fcst <- lapply(probs_fcst, .drop_dims)
  }
  if (recipe$Analysis$Workflow$Probabilities$save %in%
      c('all', 'bins_only')) {
    ## TODO: Add hcst and obs
    ## Saving only forecast probabilities for now
    # save_probabilities(recipe = recipe, probs = probs_hcst,
    #                    data_cube = data$hcst, agg = agg,
    #                    type = "hcst")
    # save_probabilities(recipe = recipe, probs = probs_obs,
    #                    data_cube = data$obs, agg = agg,
    #                    type = "obs")
    if (!is.null(data$fcst)) {
      save_probabilities(recipe = recipe, probs = probs_fcst,
                         data_cube = data$fcst, agg = agg,
                         type = "fcst")
    }
  }

  # 3. Save hindcast, fcst and obs
  if (recipe$Analysis$Workflow[[module]]$save != "none") {
    # Save forecast
    if ((recipe$Analysis$Workflow[[module]]$save %in%
           c('all', 'exp_only', 'fcst_only')) && !is.null(data$fcst)) {
      save_forecast(recipe = recipe, data_cube = data$fcst, type = 'fcst')
    }
    # Save hindcast
    if (recipe$Analysis$Workflow[[module]]$save %in%
        c('all', 'exp_only')) {
      if (dim(data$hcst$data)['sweek'] > 1) {
        data$hcst <- CST_Subset(data$hcst, along = 'sweek',
                                indices = (dim(data$hcst$data)['week'] + 1) / 2)
      }
      save_forecast(recipe = recipe, data_cube = data$hcst, type = 'hcst')
    }
    # Save observations
    if (recipe$Analysis$Workflow[[module]]$save == 'all') {
      if (dim(data$obs$data)['sweek'] > 1) {
        data$obs <- CST_Subset(data$obs, along = 'sweek',
                               indices = (dim(data$obs$data)['sweek'] + 1) / 2)
      }
      save_observations(recipe = recipe, data_cube = data$obs)
    }
  }

  # 4. Save metrics
  if (!is.null(metrics)) {
    recipe$Run$output_dir <- file.path(original_output_dir, "outputs", "Skill")
    save_metrics(recipe = recipe,
                 metrics = skill_metrics,
                 data_cube = data$obs, agg = agg,
                 outdir = recipe$Run$output_dir)
  }
  recipe$Run$output_dir <- original_output_dir
}
