box::use(
  shiny[moduleServer, NS, tagList, reactive, req, uiOutput, renderUI, div,observeEvent, reactiveValues, reactiveValuesToList,
    observe, reactiveVal, bindEvent, verbatimTextOutput, renderPrint, showNotification, textInput,
    br, checkboxInput, textAreaInput, column, fluidRow, updateSelectInput, updateTextAreaInput],
  bs4Dash[box],
  DT[DTOutput, renderDT, datatable, JS, editData],
  glue[glue],
  stringr[str_to_title],
  shinycssloaders[withSpinner],
  shinyFeedback[loadingButton, resetLoadingButton, feedbackDanger],
  shinyjs[hide, show, hidden, useShinyjs, disabled, enable],
  DBI[dbWriteTable, dbSendQuery],
  shinyalert[shinyalert],
  pool[poolCheckout, poolReturn],
  reactable[reactableOutput, renderReactable, reactable, colDef, JS, getReactableState, reactableTheme, reactableLang]
)

box::use(
  app/logic/fct_conn[pool, load_data, update_query, safe_db_operation],
  #app/logic/dt_utils[query_db,]
)


#' @export
ui <- function(id) {
  ns <- NS(id)
  tagList(
    useShinyjs(),

    box(
      width = 12,
      title = uiOutput(ns("title")),
      title_side = "top left",
      ribbon = TRUE,
      collapsible = FALSE,
      color = "grey",
      style = "overflow-y: auto;",
      
      div(style = "overflow-x: auto;", 
            reactableOutput(ns("table_samples")) |> 
              withSpinner(type = 7, color = "green")
      ),
      br(),br(),
      textAreaInput(ns("comments"), "Add comments", value = "") |> hidden(), 
      #verbatimTextOutput(ns("txt")),
      br(),
      fluidRow(
        column(2, loadingButton(ns("approve"), "Approve selected samples", loadingLabel = "Approve selected samples", loadingSpinner = "sync", class = "pull-right btn btn-success")),
        column(2, loadingButton(ns("reject"), "Reject selected samples", loadingLabel = "Reject selected samples", loadingSpinner = "sync", class = "pull-right btn btn-secondary"))
        ),br()
    )
  )
}

#' @export
server <- function(id, res_auth, lab, new_sample) {
  moduleServer(id, function(input, output, session) {
    
    ns <- session$ns
    
    r <- reactiveValues(
      action = NULL
    )

    hide("approve")
    hide("reject")
    
    output$title <- renderUI({
      paste(toupper(lab), "APPROVAL REQUIRED")
    })
    
    is_admin <- reactive({
      admin <- FALSE
      if(reactiveValuesToList(res_auth)$designation %in% c("admin", "lab manager")){
        admin <- TRUE
      }
      admin
    })
    
    # Reactive value to trigger table reload
    reload_table <- reactiveVal(0)
    
    sample_data <- reactive({
      
      # Depend on reload_table to trigger re-fetching data
      reload_table()
   
      load_data(glue("SELECT t2.*
                           FROM {lab}_status t1
                           LEFT JOIN {lab}_samples t2 ON t1.sample_id=t2.sample_id
                           WHERE t1.status='Sample logged'
                           ORDER BY t1.sample_id"),
                pool)
    }) |> 
      bindEvent(reload_table())  # Only update when reload_table changes
    
    edit_data <- reactiveVal(NULL)
    
    
    js <- function(dtid, cols, ns = identity) {
      code <- vector("list", length(cols))
      for(i in seq_along(cols)) {
        col <- cols[i]
        code[[i]] <- c(
          sprintf(
            "$('body').on('click', '[id^=checkb_%d_]', function() {",
            col),
          "  var id = this.getAttribute('id');",
          sprintf(
            "  var i = parseInt(/checkb_%d_(\\d+)/.exec(id)[1]);",
            col),
          "  var value = $(this).prop('checked');",
          sprintf(
            "  var info = [{row: i, col: %d, value: value}];",
            col),
          sprintf(
            "  Shiny.setInputValue('%s', info);",
            ns(sprintf("%s_cell_edit:DT.cellInfo", dtid))
          ),
          "});"
        )
      }
      do.call(c, code)
    }
    
    
    output$table_samples <- renderReactable({
      new_sample()
      dt <- sample_data()
      colnames(dt) <- stringr::str_to_title(gsub("_", " ", names(dt)))
      reactable(
        dt,
        sortable = FALSE,
        pagination = FALSE,
        searchable = TRUE,
        selection = "multiple", 
        onClick = "select",
        height = "auto",     
        compact = TRUE,
        defaultColDef = reactable::colDef(
          minWidth = 100, maxWidth = 200, width = 150,
          headerStyle = list(`text-transform` = "uppercase",color = "hsl(203, 15%, 47%)")
        ),
        columns = list(
          `sample id` = colDef(
            sticky = "left",
            # Add a right border style to visually distinguish the sticky column
            style =  list(backgroundColor = "#f7f7f7"),
            headerStyle =  list(backgroundColor = "#f7f7f7")
          )
        ),
        highlight = TRUE,
        language = reactableLang(
          noData = "No data found",
          pageInfo = "{rowStart}\u2013{rowEnd} of {rows} data"
        ),
        theme = reactableTheme(
          highlightColor = "#f3fafb",
          borderColor = "hsl(0, 0%, 93%)",
          headerStyle = list(borderColor = "hsl(0, 0%, 90%)"),
          rowStyle = list(
            cursor = "pointer",
            "&:hover" = list(backgroundColor = "rgba(243, 250, 251, 0.7)")
          )
        ),
        width = "100%",
        style = list(maxWidth = "100%", overflowX = "auto",
                     fontFamily = "Work Sans, sans-serif", fontSize = "0.875rem")
      )
    })
    
    selected <- reactive(getReactableState("table_samples", "selected"))

    
    # Reactive value to store selected rows with their corresponding checkbox values
    selected_rows <- reactiveVal(list())
    
    # Observe the checkbox edit event
    observe({
      if(!is.null(selected())){
        show("comments")
        show("approve")
        show("reject")
      } else {
        hide("comments")
        hide("approve")
        hide("reject")
      }
    })
    
    
    approved_data <- reactive({
      data.frame(
        sample_id = sample_data()[selected(),"sample_id"],
        #approved = TRUE,
        updated_by = reactiveValuesToList(res_auth)$user,
        date_updated = Sys.Date(),
        comments = ifelse(input$comments == "", "", input$comments)
      )
    })    
    
    observeEvent( input$approve , {
      
      if(!is.null(selected())){
          if(isTRUE(is_admin())){
            dt <- approved_data()
            dt$status = "approved"
            
            # conn <- poolCheckout(pool)
            # on.exit({
            #   poolReturn(conn)  # Always return connection to pool
            # })
            #safe_db_operation(pool, dbWriteTable(conn, glue({lab},"_approval"), dt, append=T))      
            safe_db_operation(
              pool,
              operations = list(
                list(
                  type = "write",
                  table = paste0(lab, "_approval"),
                  data = dt,
                  append = TRUE
                )
              ),
              transaction = TRUE
            )
            
            for(i in 1:nrow(dt)){
               update_query <- glue("UPDATE {lab}_status SET status='Sample approved', last_update='{Sys.Date()}' WHERE sample_id='{dt$sample_id[i]}'")  
              # conn <- poolCheckout(pool)
              # on.exit({
              #   poolReturn(conn)  # Always return connection to pool
              # })
              # 
              # dbSendQuery(conn, update_query)
              
              safe_db_operation(
                pool, 
                operations = list( 
                  list( 
                    type = "query", 
                    sql = update_query 
                  )
                ),
                transaction = TRUE)
              
              
            }
            shinyalert("Success!", "Samples approved", type = "success")
            resetLoadingButton("approve")
            hide("reject")
            hide("approve")
            hide("comments")
            updateTextAreaInput(session, "comments", "Add comments", value="")
            # Increment reload_table to trigger table reload
            reload_table(reload_table() + 1)
            r$action <- input$approve
          } 
        } else {
          shinyalert("Warning!", "Select at least one sample to approve.", type="warning")
        }
      })
    
    
    # Reject

    observeEvent( input$reject , {
      if(isTRUE(is_admin())){
        if(input$comments == ""){
          shinyalert("Warning!", "Add comments.", type = "warning") 
          feedbackDanger("comments", show= TRUE, text="")
          resetLoadingButton("reject")
        } else {
          shinyalert(
            title = "Confirm", 
            text = "Do you really want to reject the selected samples?", 
            inputValue = NULL,
            showConfirmButton = TRUE,
            showCancelButton = TRUE,
            confirmButtonText = "Yes",
            confirmButtonCol = "#3d9970",
            cancelButtonText = "Cancel",
            type = "warning",
            callbackR = function(value) {
              # This function will be called when the user clicks "Yes" or "Cancel"
              if (value) {
                # User clicked "Yes"
                dt <- approved_data()
                dt$status = "rejected"
                # dbWriteTable(conn, glue({lab},"_approval"), dt, append=T)
                # 
                safe_db_operation(
                  pool,
                  operations = list(
                    list(
                      type = "write",
                      table = paste0(lab, "_approval"),
                      data = dt,
                      append = TRUE
                    )
                  ),
                  transaction = TRUE
                )
                
                for(i in 1:nrow(dt)){
                  # conn <- poolCheckout(pool)
                  # on.exit({
                  #   poolReturn(conn)  # Always return connection to pool
                  # })
                  
                  update_query <- glue("UPDATE {lab}_status SET status='Sample rejected', last_update='{Sys.Date()}' 
                                       WHERE sample_id='{dt$sample_id[i]}'")
                  # dbSendQuery(conn, update_query)
                  safe_db_operation(
                    pool, 
                    operations = list( 
                      list( 
                        type = "query", 
                        sql = update_query 
                      )
                    ),
                    transaction = TRUE)
                }
                
                hide("reject")
                hide("approve")
                hide("comments")
                updateTextAreaInput(session, "comments", "Add comments", value="")
                # Increment reload_table to trigger table reload
                reload_table(reload_table() + 1)
                r$action <- input$reject
              }
            }
          )
          
          resetLoadingButton("reject")
        }
      } 
    })
    
    r

  })
}
