#' @title AutoNN
#' @description Automatic Neural Network Modeling for Time Series Forecasting
#'
#' @param Data Time series data used for the study
#' @param IN Maximum number of input nodes
#' @param size Maximum number of hidden nodes
#' @param out_forecast Number of output periods to be predicted
#'
#' @return A list containing:
#' \itemize{
#'   \item Best_Model
#'   \item Final_Results
#'   \item AutoNN_model
#'   \item Fitted
#'   \item Forecast
#' }
#'
#' @examples
#' ts_data  <- nottem
#' Model <- AutoNN(Data = ts_data , IN = 3, size = 5, out_forecast = 12)
#' Model
#'
#'
#' @references
#' 1. Shankar, S. V., Chandel, A., Gupta, R. K., Sharma, S., Chand, H., Aravinthkumar, A., & Ananthakrishnan, S. (2025). Comparative study on key time series models for exploring the agricultural price volatility in potato prices. Potato Research, 68(2), 1189-1207. DOI  https://doi.org/10.1007/s11540-024-09776-3
#'
#' @export

AutoNN <- function(Data, IN, size, out_forecast) {
  # Split data into training and testing
  D <- length(Data) - out_forecast
  Training <- Data[1:D]
  Testing <- Data[-c(1:D)]

  # Initialize empty vectors to store results
  Training_RMSE <- c()
  Training_MAPE <- c()
  Training_MAE <- c()
  Model <- matrix(ncol = 2, nrow = 0)
  Testing_RMSE <- c()
  Testing_MAPE <- c()
  Testing_MAE <- c()

  # Loop over the number of inputs and hidden neurons
  for (i in 1:IN) {
    for (n in 1:size) {
      ANN_model <- forecast::nnetar(Training, p = i, size = n, scale.inputs = TRUE, repeats = 25)
      ANN_predict <- forecast::forecast(ANN_model, h = out_forecast)
      M <- c(i, n)
      a <- IN + 1
      b <- length(Training)

      # Calculate Training Metrics
      a_RMSE <- MLmetrics::RMSE(Training[a:b], ANN_model$fitted[a:b])
      a_MAPE <- MLmetrics::MAPE(Training[a:b], ANN_model$fitted[a:b]) * 100
      a_MAE <- MLmetrics::MAE(Training[a:b], ANN_model$fitted[a:b])

      # Calculate Testing Metrics
      b_RMSE <- MLmetrics::RMSE(Testing, ANN_predict$mean)
      b_MAPE <- MLmetrics::MAPE(Testing, ANN_predict$mean) * 100
      b_MAE <- MLmetrics::MAE(Testing, ANN_predict$mean)

      # Append results to the vectors
      Model <- rbind(Model, M)
      Training_RMSE <- c(Training_RMSE, a_RMSE)
      Training_MAPE <- c(Training_MAPE, a_MAPE)
      Training_MAE <- c(Training_MAE, a_MAE)
      Testing_RMSE <- c(Testing_RMSE, b_RMSE)
      Testing_MAPE <- c(Testing_MAPE, b_MAPE)
      Testing_MAE <- c(Testing_MAE, b_MAE)
    }
  }

  # Combine all metrics into a final dataframe
  final <- data.frame(
    Input_Node = Model[, 1],
    Hidden_Node = Model[, 2],
    Training_RMSE = Training_RMSE,
    Training_MAPE = Training_MAPE,
    Training_MAE = Training_MAE,
    Testing_RMSE = Testing_RMSE,
    Testing_MAPE = Testing_MAPE,
    Testing_MAE = Testing_MAE
  )

  # Find the best model based on the minimum Testing_MAPE
  best_model <- final[which.min(final$Testing_MAPE), ]
  input_node <- best_model$Input_Node
  hidden_node <- best_model$Hidden_Node

  # Build the final AutoANN model using the best parameters
  AutoNN_model <- forecast::nnetar(Training, p = input_node, size = hidden_node, scale.inputs = TRUE, repeats = 25)

  # Extract fitted values
  fitted_AutoNN_model <- AutoNN_model$fitted

  # Forecast using the best AutoANN_model
  forecast_AutoNN_model <- forecast::forecast(AutoNN_model, h = length(Testing))

  # Return the results as a list
  return(list(
    Best_Model = best_model,
    Final_Results = final,
    AutoNN_model = AutoNN_model,
    Fitted = fitted_AutoNN_model,
    Forecast = forecast_AutoNN_model
  ))
}
