# ---------------------------
#
# Script name: aggregate_server.R
# data4health Shiny app - aggregate server
#
# Purpose of script: creates the server module for the
# aggregation tab of the shiny app
# Author: Daniela Lührsen
# Date Created: 2026-02
# Email: daniela.luhrsen@bsc.es
#
# ---------------------------

aggregate_server <- function(id, data_store, app_state) {

  moduleServer(id, function(input, output, session) {

    ns <- NS(id)

    # load data --------------------------------------------------------------
    # UI - for loading data
    output$agg_load <- renderUI({
      # if user is coming from the cleaning tab,
      # show message that data is loaded and give option to upload new data
      # if (app_state$go_aggregation) {
      if (length(data_store$get()) != 0) {
        tagList(
          column(
            width = 6,
            helpText(paste0("The pre-processed data from the previous ",
                            "tab is automatically loaded."))
          ),
          column(
            width = 6,
            helpText(paste0("If you wish to use a different dataset, you ",
                            "can upload it here. Each row should be a case, ",
                            "and the columns (with headers) are information ",
                            "about it.")),
            fileInput(ns("agg_file_input"), "",
                      accept = c(".csv", ".dbf", ".dbc", ".rds",
                                 ".xlsx", ".xls", ".json"),
                      multiple = TRUE)
          )
        )
      # if user is coming directly to aggregation tab, show only the file input
      } else {
        helpText(paste0("Each row should be a case, and the columns ",
                        "(with headers) are information about it."))
        fileInput(ns("agg_file_input"), "",
                  accept = c(".csv", ".dbf", ".dbc", ".rds",
                             ".xlsx", ".xls", ".json"),
                  multiple = TRUE)
      }
    })

    # load dataset for filter
    observeEvent(input$agg_file_input, {
      inFile <- input$agg_file_input
      data_store$set(data4health::d4h_load(inFile$datapath))
    })

    # agregate filters -------------------------------------------------------

    # give correct columnnames choices in the aggregate section
    observe({
      req(data_store$get())
      x <- colnames(data_store$get())
      updateSelectInput(session, "agg_time_col", choices = x,  selected = "-")
      updateSelectInput(session, "agg_space_col", choices = x,  selected = "-")
      updateSelectInput(session, "agg_option_col", choices = x,  selected = "-")
    })

    # CODE - store code in a reactive value,
    # so it can be used both by the ui and the server
    code_aggregate <- reactiveVal()
    observe({
      req(data_store$get())

      timestep <- if (grepl("week", input[["agg_time_col"]],
                            ignore.case = TRUE)) {
        "week"
      } else if (grepl("month", input[["agg_time_col"]], ignore.case = TRUE)) {
        "month"
      } else {
        "month"
      }

      code_aggregate(paste0("df <- d4h_aggregate(data = df",
                            ifelse(input[["agg_space_col"]] == "", "",
                                   paste0(", \n                    ",
                                          "space_col = '",
                                          input[["agg_space_col"]], "'")),
                            ifelse(input[["agg_space_col"]] == "", "",
                                   paste0(", \n                    ",
                                          "all_spaces = unique(df[['",
                                          input[["agg_space_col"]], "']])")),
                            ifelse(input[["agg_time_col"]] == "", "",
                                   paste0(", \n                    ",
                                          "time_col = '",
                                          input[["agg_time_col"]], "'")),
                            ifelse(input[["agg_time_col"]] == "", "",
                                   paste0(", \n                    ",
                                          "all_times = seq(min(df[['",
                                          input[["agg_time_col"]],
                                          "']], na.rm = TRUE),\n",
                                        "                                    ",
                                          "max(df[['",
                                          input[["agg_time_col"]],
                                          "']], na.rm = TRUE),\n",
                                        "                                    ",
                                          "by = '",
                                          timestep, "')")),
                            ifelse(is.null(input[["agg_option_col"]]), "",
                                   paste0(",\n                     add_col = ",
                                    format_vector(input[["agg_option_col"]]))),
                            ")"))
    })

    # UI - code to aggregate
    output$aggregate_codeui <- renderUI({
      if (hide8_count() %% 2 == 0) {
        tagList(
          actionLink(ns("hide8"), "Click here to show the code",
                     icon("angle-down"),
                     style = "color: #bfbfbf; text-decoration: none")
        )
      } else {
        tagList(
          actionLink(ns("hide8"), "Click here to hide the code",
                     icon("angle-up"),
                     style = "color: #bfbfbf; text-decoration: none"),
          tags$br(),
          shinyAce::aceEditor(ns("code_aggregate"), mode = "r",
                              theme = "tomorrow", height = "150px",
                              value = code_aggregate())
        )
      }
    })
    hide8_count <- reactiveVal(0)
    observeEvent(input$hide8, {
      hide8_count(hide8_count() + 1)
    })

    # EXECUTE - run code to delete empty columns
    observeEvent(input$aggregate_button, {
      req(data_store$get())

      code <- code_aggregate()

      env <- new.env(parent = asNamespace("data4health"))
      env$input <- input
      env$df <- data_store$get()
      tryCatch({
        withCallingHandlers({

          out <- eval(parse(text = code), envir = env)

          # Now update the reactiveVal with the new data
          data_store$set(out)
        },
        # show messages in green
        message = function(m) {
          showNotification(conditionMessage(m), type = "message")
          invokeRestart("muffleMessage")
        })
      }, error = function(e) {
        showNotification(paste0("Error:", conditionMessage(e)), type = "error")
      })
    })

    # download the cleaned data
    output$download_aggregate <- downloadHandler(
      filename = function() {
        paste0("d4h_aggregate_", format(Sys.time(), "%Y%m%d_%H%M"), ".csv")
      },
      content = function(file) {
        write.csv(data_store$get(), file)
      }
    )

    # if proceed to Visualisation button is clicked,
    # set go_visualisation to TRUE, app.R will use it to updateTabsetPanel
    observeEvent(input$go_aggregation_visualisation, {
      req(data_store$get())
      app_state$go_visualisation <- TRUE
    })
  })
}

### END
