#'Read recipe YAML file and create and store logfile info
#'
#'The purpose of this function is to read the recipe configuration for Auto-S2S
#'workflows and create logfiles stored in an the output directory specified in 
#'the recipe. It returns an object of class logger that stores information on 
#'the recipe configuration and errors.
#'
#'@param recipe_file path to a YAML file with Auto-S2S configuration recipe
#'@param disable_checks whether to disable the recipe checks
#'@param unique_ID whether to add a unique ID to the output directory
#'@return list contaning recipe with logger, log file name and log dir name
#'
#'@import log4r
#'@import yaml
#'
#'@examples
#'setwd("/esarchive/scratch/vagudets/repos/auto-s2s/")
#'library(yaml)
#'recipe <- prepare_outputs("modules/data_load/recipe_1.yml")
#'info(recipe$Run$logger, "This is an info message")
#'
#'@export

prepare_outputs <- function(recipe_file,
                            disable_checks = FALSE,
                            uniqueID = TRUE,
                            restructure = TRUE) {
  # recipe_file: path to recipe YAML file
  # disable_checks: If TRUE, does not perform checks on recipe
  # disable_uniqueID: If TRUE, does not add a unique ID to output dir
  recipe <- read_yaml(recipe_file, eval.exp = TRUE)
  recipe$recipe_path <- recipe_file
  recipe$name <- tools::file_path_sans_ext(basename(recipe_file))

  output_dir = recipe$Run$output_dir
  # Create output folders
  if (!uniqueID) {
    folder_name <- paste0(gsub(".yml", "", gsub("/", "_", recipe$name)))
  } else {
    folder_name <- paste0(gsub(".yml", "", gsub("/", "_", recipe$name)), "_",
                          gsub(" ", "", gsub(":", "", gsub("-", "",
                                                           Sys.time()))))
  }
  recipe$Run$output_dir <- file.path(output_dir, folder_name)
  print("Saving all outputs to:")
  print(paste0(output_dir, folder_name))
  if (dir.exists(file.path(output_dir, folder_name))) {
    warning("The output directory already exists and files may be overwritten.")
  } else {
    dir.create(file.path(output_dir, folder_name, 'outputs'),
               recursive = T, showWarnings = F)
  }
  dir.create(file.path(output_dir, folder_name, 'logs', 'recipes'),
             recursive = T, showWarnings = F)
  # Create log output file
  logfile <- file.path(output_dir, folder_name, 'logs', 'main.log')
  file.create(logfile)

  # Set default behaviour of logger
  if (is.null(recipe$Run)) {
    recipe$Run <- list(Loglevel = 'INFO', Terminal = TRUE)
  }
  if (is.null(recipe$Run$Loglevel)) {
    recipe$Run$Loglevel <- 'INFO'
  }
  if (!is.logical(recipe$Run$Terminal)) {
    recipe$Run$Terminal <- TRUE
  }
  # logger set-up
  if (recipe$Run$Terminal) {
    logger <- log4r::logger(threshold = recipe$Run$Loglevel,  
                            appenders = list(console_appender(layout = .custom_log_layout()),
                                             file_appender(logfile, append = TRUE,   
                                                           layout = .custom_log_layout())))
  } else {
    logger <- log4r::logger(threshold = recipe$Run$Loglevel,
                            appenders = list(file_appender(logfile, append = TRUE,             
                                             layout = .custom_log_layout())))
  }
  recipe$Run$logger <- logger
  recipe$Run$logfile <- logfile

  # Disclosure
  disclosure_message <- 
    "SUNSET: SUbseasoNal to decadal climate forecast post-processing and asSEssmenT suite
    Copyright (C) 2024 BSC-CNS
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>."

  for (i in disclosure_message) {
    info(recipe$Run$logger, retrieve = TRUE, i)
  }
  # Set up default filesystem
  if (is.null(recipe$Run$filesystem)) {
    recipe$Run$filesystem <- "esarchive"
    warn(recipe$Run$logger, retrieve = TRUE,
         "Filesystem not specified in the recipe. Setting it to 'esarchive'.")
  }
  # Restructure the recipe to make the atomic recipe more readable
  if (restructure) {
  recipe <- restructure_recipe(recipe)
  }
  # Pre-processing: convert all strings in Analysis section to lowercase,
  # except for system, reference and region names
  system <- recipe$Analysis$Datasets$System
  reference <- recipe$Analysis$Datasets$Reference
  region <- recipe$Analysis$Region
  variable <- recipe$Analysis$Variables
  recipe$Analysis <- rapply(recipe$Analysis, tolower,
                            how = "replace",
                            classes = "character")
  recipe$Analysis$Datasets$System <- system
  recipe$Analysis$Datasets$Reference <- reference
  recipe$Analysis$Region <- region
  recipe$Analysis$Variables <- variable

  # Run recipe checker
  if (disable_checks) {
    warn(recipe$Run$logger, retrieve = TRUE,
         "Recipe checks disabled. The recipe will not be checked for errors.")
  } else {
    recipe <- check_recipe(recipe)
  }
  # Create a copy of the recipe and remove the logger
  recipe_copy <- recipe
  recipe_copy$Run$logger <- NULL
  # Copy recipe to output folder
  write_yaml(recipe_copy,
             file = file.path(output_dir, folder_name, 'logs', 'recipes',
                              paste0(recipe$name, ".yml")))
  return(recipe)
}

.custom_log_layout <- function() {
  # Custom modification of the default log4r log layout to remove ANSI
  # formatting from log messages when outputting to files.
  time_format <- "%Y-%m-%d %H:%M:%S"
  function(level, retrieve, ...) {
    if (retrieve) {
      msg <- paste0(..., collapse = "")
      # Strip msg of ANSI formatting
      # msg <- ansi_strip(msg)
      sprintf("%-5s [%s] %s\n", level, Sys.time(), msg)
    }
  }
} 
