#' Generate Training and Evaluation Indices for Cross-Validation
#'
#' This function generates training and evaluation indices based on different cross-validation methods.
#' @author Theertha Kariyathan, \email{theertha.kariyathan@bsc.es}
#' 
#' @param eval.method Character. The cross-validation method. Options include:
#'   -\code{leave-k-out}: Leaves out \code{k} points at a time for evaluation.
#'   -\code{retrospective}: Uses past data for training and a future point for evaluation.
#'   -\code{in-sample}: Uses the entire dataset for both training and evaluation.
#'   -\code{hindcast-vs-forecast}: Uses a subset \code{amt.points_cor} for evaluation while training on \code{amt.points}.
#'   
#' @param amt.points Integer. Total number of points in the dataset.
#' @param amt.points_cor Integer. Number of points for evaluation in the \code{hindcast-vs-forecast} method.
#' @param k Positive integer. Default = 1.
#' In method \code{leave-k-out}, \code{k} is expected to be odd integer, indicating the number of points to leave out.
#' In method \code{retrospective}, \code{k} can be any positive integer, indicating when to start. 
#' @param tail.out Logical for method \code{leave-k-out}. Default = TRUE.  
#'  TRUE to remove both extremes keeping the same sample size for all k-folds 
#'  (e.g. amt.points=50, k=3, eval.dexes=1, train.dexes={3,49}). 
#'  FALSE to remove only the corresponding tail 
#'  (e.g. amt.points=50, k=3, eval.dexes=1, train.dexes={3,50})
#' @return A list of lists, where each element contains:
#'   \code{eval.dexes}: Indices of evaluation points.
#'   \code{train.dexes}: Indices of training points.
#'
#' @examples
#' # Leave-k-out cross-validation
#' CST_TrainIndex("leave-k-out", amt.points = 10, amt.points_cor = 5, k = 3)
#' # Retrospective cross-validation
#' CST_TrainIndex("retrospective", amt.points = 10, amt.points_cor = 5, k = 3)
#' # In-sample validation
#' CST_TrainIndex("in-sample", amt.points = 10, amt.points_cor = 5)
#' # Hindcast vs. Forecast validation
#' CST_TrainIndex("hindcast-vs-forecast", amt.points = 10, amt.points_cor = 5)
#'
#' @export
CST_TrainIndex <- function(eval.method, amt.points, amt.points_cor, 
                           k = 1, tail.out = TRUE) {
  
  if (is.null(k) || k >= amt.points || k < 1 || k %% 2 == 0 ) { 
    stop("k needs to be a positive odd integer less than the amt.points")
  }
  
  if ( k %% 2 == 0 ) { 
    warning("k is expected to be an odd integer")
  }
  
  if (eval.method == "leave-k-out") {
    if (k == 1) {
      tail.out == TRUE
    }
    amt.seq <- 1:amt.points
    strike = (k - 1) / 2
    alt_amt.seq <- c(tail(amt.seq, strike), amt.seq, head(amt.seq, strike))
    
    dexes.lst <- lapply(seq(1, amt.points), function(x, kfold = k) {
      if (tail.out) {
        ind = alt_amt.seq[x:(x + (kfold - 1))]
      } else{
        ind = ((x - strike):(x + strike))
        ind = ind[ind > 0 & ind <= amt.points]
      }
      return(list(eval.dexes = x,  train.dexes = amt.seq[!(amt.seq %in% ind)]))
    })
  } else if (eval.method == "retrospective") {
    # k can be any integer indicating the when to start
    dexes.lst <- base::Filter(length, lapply(seq(1, amt.points),
                                             function(x, mindata = k) {
                                               if (x > k) { 
                                                 eval.dexes <- x
                                                 train.dexes <- 1:(x-1)
                                                 return(list(eval.dexes = x,
                                                             train.dexes = 1:(x-1)))
                                               }})) 

  } else if (eval.method == "in-sample") {
    dexes.lst <- list(list(eval.dexes = seq(1, amt.points), 
                           train.dexes = seq(1, amt.points)))
  } else if (eval.method == "hindcast-vs-forecast") {
    dexes.lst <- list(list(eval.dexes = seq(1,amt.points_cor),
                           train.dexes = seq(1, amt.points)))
  } else {
    stop(paste0("unknown sampling method: ", eval.method))
  }
  
  return(dexes.lst)
} 

