server <- function(input, output, session) {
  # initilisation de la liste des valeurs réactives-----
  r <- reactiveValues(
    base = NULL, # la base choisie par l'utilisateur
    schemas_pour_base = NULL, # la liste des schémas de la base choisie par l'utilisateur
    schema = "Tous", # le schéma choisi par l'utilisateur
    tables_pour_schema = NULL, # la liste des schémas de la base choisie par l'utilisateur
    table = "Toutes", # la table choisie par l'utilisateur
    metadata_csv = NULL, # table de métadonnées à télécharger
    nom_meta_csv = NULL, # nom du fichier CSV contenant les métadonnées à télécharger
    selected_metadata = NULL, # table de métadonnées à afficher
    commentaire = NULL, # commentaires de base/schéma/table/
    fil_ariane = "",
    title_metadata = NULL, # Titre de présentation des métadonnées
    selected_data = NULL, # table sélectionnée
    isSpatial = FALSE, # booléen pour identifier les tables spatiales
    role = "dreal", # on initialise la connexion au SGBD avec le rôle de connexion dreal par défaut
    acces = FALSE,
    selected_row10 = NULL,
    table_rows = NULL,
    table_size = NULL,
    showDataMapTabs = FALSE
  )

  # Onglet explorer : inputs---------
  observeEvent(input$base, {
    req(input$base)
    r$base <- input$base
    # on réinitialise la liste des objets réactifs à chaque changement de input$base
    r$schema <- "Tous"
    r$table <- "Toutes"
    r$schemas_pour_base <- dplyr::filter(db_schema_list, base == r$base)

    # Vérifiez que schemas_pour_base a des éléments avant de mettre à jour
    if(nrow(r$schemas_pour_base) > 0) {
      shinygouv::updateSelectInput_dsfr(session = session, inputId = "schema",
                                        choices = c("Tous", r$schemas_pour_base$nom_schema %>%
                                                      setNames(r$schemas_pour_base$display_name)),
                                        selected = "Tous")
    } else {
      shinygouv::updateSelectInput_dsfr(inputId = "schema", choices = c("Tous"), selected = "Tous")
    }
  })

  observeEvent(c(r$schemas_pour_base, input$schema), {
    req(input$schema)
    r$schema <- input$schema
    r$table <- "Toutes"
    req(r$schemas_pour_base, r$schema)

    if (r$schema == "Tous") {
      r$tables_pour_schema <- data.frame()  # Pas de tables à afficher
    } else {
      r$tables_pour_schema <- tb_sch_base %>%
        dplyr::filter(base == r$base, nom_schema == r$schema)
    }
    if(length(r$tables_pour_schema) > 0) {
      shinygouv::updateSelectInput_dsfr(session = session, inputId = "table",
                                        choices = c("Toutes", r$tables_pour_schema$table), selected = "Toutes")
    } else {
      shinygouv::updateSelectInput_dsfr(session = session, inputId = "table", choices = c("Toutes"), selected = "Toutes")
    }
  })

  # Recherche plein texte : résultats de recherche -------------------------------------
  observeEvent(input$search_button, {
    r$filtered_data <- NULL
    r$message_recherche_infructueuse <- ""
    # filtrer la table de recherche plein texte selon le texte recherché
    req(input$search_784_input)
    search_results <- base_recherche_txt %>%
      dplyr::filter(grepl(input$search_784_input, description, ignore.case = TRUE)) %>%
      dplyr::select(base, nom_schema, nom_table)

    if (nrow(search_results) > 0) {
      search_results <- search_results %>%
        dplyr::left_join(tables_catalog %>%
                           dplyr::filter(nom_col == "") %>%
                           dplyr::select(base, nom_schema, nom_table, commentaire),
                         by = c("base", "nom_schema", "nom_table")) %>%
        dplyr::rename(`Libellé` = commentaire) %>%
        dplyr::distinct()

      r$filtered_data <- search_results %>%
        dplyr::mutate(
          base_js_on_click = paste0( '"Shiny.setInputValue(\'clic_base\', \'', base, '\'); '),
          schema_js_on_click = paste0(base_js_on_click,
                                      'Shiny.setInputValue(\'clic_schema\', \'', nom_schema, '\'); '),
          table_js_on_click = paste0(schema_js_on_click,
                                     'Shiny.setInputValue(\'clic_table\', \'', nom_table, '\'); '),
          # on ajoute les inputs clic_schema = "Tous" et clic_table = "Toutes"
          base_js_on_click = paste0(base_js_on_click, 'Shiny.setInputValue(\'clic_schema\', \'Tous\'); ',
                                    'Shiny.setInputValue(\'clic_table\', \'Toutes\'); '),
          schema_js_on_click = paste0(schema_js_on_click, 'Shiny.setInputValue(\'clic_table\', \'Toutes\'); '),
          nav_onglet = 'Shiny.onInputChange(\'nav_to_explorer\', Math.random()); return false;">',
          base =       paste0('<a href = "#" onclick = ', base_js_on_click, nav_onglet, base, '</a>'),
          nom_schema = paste0('<a href = "#" onclick = ', schema_js_on_click, nav_onglet, nom_schema, '</a>'),
          nom_table =  paste0('<a href = "#" onclick = ', table_js_on_click, nav_onglet, nom_table, '</a>')
        ) %>%
        select(-nav_onglet, -ends_with("_js_on_click"))
    } else {
      r$message_recherche_infructueuse <- tagList(
        p("Aucun lot de données ne correspond à votre recherche,
            veuillez la renouveler ou explorer les bases de données disponibles (2e onglet)")
      )
    }

  })

  # Affichage des résultats dans un tableau
  output$search_results <- DT::renderDataTable({
    DT::datatable(r$filtered_data, escape = FALSE,
                  options = list(pageLength = 20, lengthMenu = c(20, 50, 100),
                                 language = list(url = 'https://cdn.datatables.net/plug-ins/1.10.21/i18n/French.json')))
  })

  # Affichage du message si aucun résultat n'est trouvé
  output$search_message <- renderUI({
    r$message_recherche_infructueuse
  })

  # Recherche plein texte : inputs -------------------------------------
  # Observer l'événement nav_to_explorer pour cliquer sur visualiser les métadonnées après avoir mis à jour les inputs de sélection base/schema/table
  observeEvent(input$nav_to_explorer, {
    duree_totale = 3 * 250
    # On met à jour la base choisie dans le selectInput
    shinygouv::updateSelectInput_dsfr(session = session, inputId = "base",
                                      choices = bases_avec_commentaires$base,
                                      selected = input$clic_base)
    # on prévoit un peu de délai avant de lancer la suite
    shinyjs::delay(ms = duree_totale, expr = {
      req(input$clic_base == input$base)
      message("Mise à jour de  input base réalisée : ", input$base, ".")
      req(r$schemas_pour_base)
      # On met à jour le schema choisi dans le selectInput
      shinygouv::updateSelectInput_dsfr(inputId = "schema", session = session, selected = input$clic_schema,
                                        choices = unique(c("Tous", r$schemas_pour_base$nom_schema)))
      shinyjs::delay(ms = duree_totale/3*2, expr = {
        req(input$clic_schema == input$schema)
        message(paste0("Mise à jour de l'input schema réalisée : ", input$schema))
        # Vérification que la liste de choix des tables est prête avant de poursuivre
        req(r$tables_pour_schema )
        # Mise à jour de l'input table
        shinygouv::updateSelectInput_dsfr(inputId = "table", session = session, selected = input$clic_table,
                                          choices = c("Toutes", r$tables_pour_schema$table))

        shinyjs::delay(ms = duree_totale/3, expr = {
          req(input$clic_table == input$table)
          message(paste("Mise à jour de l'input table réalisée : ", input$table))
          shinyjs::click("visualiserMetadata")
          shinyjs::runjs("navigateToExplorer();")
         })
      })
    })
  })


  # Afficher le tableau selected_metadata uniquement si le bouton est cliqué -------------
  observeEvent(input$visualiserMetadata, {
    r$showDataMapTabs <- FALSE
    req(input$table)
    r$table <- input$table
    req(r$schemas_pour_base, r$tables_pour_schema, r$table)
    r$selected_metadata <- NULL
    r$selected_data <- NULL
    r$metadata_csv <- NULL
    r$fil_ariane <- ""

    # Définir le fil d'Ariane une fois, indépendamment des cas spécifiques
    r$fil_ariane <- create_breadcrumb(base = r$base, schema = r$schema, table = r$table)

    if (r$table == "Toutes") {
      # on vide toutes les variables réactives liées à la table précédemment sélectionnée
      r$selected_row10 <- NULL
      r$isSpatial <- NULL
      r$table_rows <- NULL
      r$table_size <- NULL

      if (r$schema == "Tous") {
        # Cas où "Toutes" est sélectionné pour table et schema
        r$title_metadata <- paste0("Liste des schémas de la base : ", r$base)
        r$metadata_csv <- r$schemas_pour_base  %>%
          dplyr::select(-display_name)
        r$selected_metadata <- r$metadata_csv %>%
          dplyr::select(-base)
        r$nom_meta_csv <- paste("metadonnees", r$base, Sys.Date(), sep = ".")
        # Commentaire descriptif de la base
        r$commentaire <- bases_avec_commentaires %>%
          filter(base == r$base) %>%
          pull(commentaire) %>%
          unique()
      } else {
        # Cas où une base, un schéma sont sélectionnés et "Toutes" pour les tables
        r$title_metadata <- paste0("Tables du schéma : ", r$base, '.', r$schema)
        r$metadata_csv <- r$tables_pour_schema %>%
          dplyr::select(base, nom_schema, nom_table = table, commentaire)
        r$selected_metadata <- r$metadata_csv %>%
          dplyr::select(-base, -nom_schema)
        r$nom_meta_csv <- paste("metadonnees", r$base, r$schema, Sys.Date(), sep = ".")
        # commentaire descriptif du schema

        r$commentaire <- commentaires_schema %>%
          dplyr::filter(base == r$base, nom_schema == r$schema) %>%
          dplyr::filter(base == r$base, nom_schema == r$schema) %>%
          dplyr::pull(commentaire) %>%
          unique()
      }
    } else {
      # Cas où une base, un schéma, et une table sont sélectionnés
      r$title_metadata <- paste0("Dictionnaire d'attribut de la table ", r$table)
      r$metadata_csv <- tables_catalog %>%
        dplyr::filter(r$base == base, nom_schema == r$schema, nom_table == r$table)
      # dictionnaire d'attribut
      r$selected_metadata <- r$metadata_csv %>%
        dplyr::filter(nom_col != "") %>%
        dplyr::select(nom_col, commentaire, type_valeur = type_fr)
      r$nom_meta_csv <- paste("metadonnees", r$base, r$schema, r$table, Sys.Date(), sep = ".")
      # commentaire descriptif de table
      r$commentaire <- r$metadata_csv %>%
        dplyr::filter(nom_col == "") %>%
        dplyr::pull(commentaire)

      # Établir la connexion à la base de données
      conn <- datalibaba::connect_to_db(db = r$base, user = r$role)
      # Récupérer le nombre de lignes et la taille de la table
      r$table_rows <- dbGetQuery(conn, paste0("SELECT COUNT(*) AS n_rows FROM ", r$schema, ".", r$table))$n_rows
      r$table_size <- dbGetQuery(conn, paste0("SELECT pg_size_pretty(pg_relation_size('", r$schema, ".", r$table, "')) AS table_size"))$table_size
      # Fermer la connexion par prudence
      dbDisconnect(conn)
      rm(conn)
      # tenter de lire la table pour vérifier accès
      tryCatch({
        r$selected_row10 <- datalibaba::importer_data(table = r$table, schema = r$schema,
                                                      db = r$base, user = r$role, limit = 10)
      }, error = function(e) {
        message("Erreur lors de la récupération des données de la table : ", e$message)
        r$selected_row10 <- NULL
      })
      r$acces <- isTruthy(r$selected_row10)
      r$isSpatial <- any(grepl("spatial", r$selected_metadata$type_valeur))



    }
  })




  # Mettre à jour l'affichage du fil d'Ariane en utilisant les variables réactives
  output$breadcrumb_metadata <- renderUI({
    r$fil_ariane
  })
  # Mise à jour de l'affichage du titre des métadonnées (utilisation de title_metadata de dev)
  output$title_metadata <- renderUI({
    req(r$title_metadata)
    tags$h4(r$title_metadata)
  })

  # Mise à jour de l'affichage du commentaire
  output$commentaire_metadata <- renderUI({
    req(r$commentaire)
    tags$p(tags$strong("Descriptif :"), r$commentaire)
  })

  # Mise à jour des informations sur le nombre de lignes et la taille de la table
  output$table_metadata <- renderUI({
    req(r$table_rows, r$table_size)
    div(id = "div_meta", class = "fr-highlight",
        tags$p(tags$strong("Nombre de lignes :"), format(r$table_rows, big.mark = "\u202f", scientific = FALSE)),
        tags$p(tags$strong("Taille de la table :"), r$table_size)
    )
  })

  # Mise à jour du tableau de métadonnées avec options d'export CSV et pagination
  output$metadata_table <- DT::renderDataTable({
    req(r$selected_metadata)
    DT::datatable(
      r$selected_metadata,
      filter = 'bottom',  # Ajout du filtre en bas des colonnes
      extensions = 'Buttons',  # Ajout des boutons d'exportation CSV
      rownames = FALSE,
      options = list(
        dom = 'Bfrtip',
        pageLength = 20,
        lengthMenu = c(20, 50, 100),
        language = list(url = 'https://cdn.datatables.net/plug-ins/1.10.21/i18n/French.json'),
        autoWidth = FALSE,
        scrollX = TRUE,  # Activer le défilement horizontal
        buttons = list(
          list(
            extend = 'csv',
            text = 'Télécharger CSV',
            filename =  r$nom_meta_csv  # Utilisation du nom de fichier pour les métadonnées
          )
        )
      )
    )
  })


  # Rendre le bouton de visualisation des données conditionnellement (seulement si métadonnées visualisées ET droits accès à la table ok)
  output$viz_data <- renderUI({
    req(r$acces)
    if(input$table != "Toutes") {
      shinygouv::actionButton_dsfr("data_a_viz", "Visualiser les données", class = "fr-my-3w")
    } else {
      return(NULL)
    }
  })

  observeEvent(input$data_a_viz, {
    r$showDataMapTabs <- TRUE
  })

  output$conditional_tabs <- renderUI({
    if (r$showDataMapTabs) {
      tabsetPanel_dsfr(
        id = "data_map_tabs",
        tabPanel_dsfr(
          id = "data_preview_tab",
          title = "Données",
          content = fluidPage_dsfr(
            uiOutput("data_table_preview_title"),
            DT::dataTableOutput("data_table_preview")
          )
        ),
        tabPanel_dsfr(
          id = "map_tab",
          title = "Aperçu spatial",
          content = fluidPage_dsfr(
            uiOutput("map_title"),
            uiOutput("map_message"),
            leaflet::leafletOutput("map", height = "600px")
          )
        )
      )
    } else {
      NULL
    }
  })

  # Visualiser les données attributaires de la table-----------------------------------------
  observeEvent(input$data_a_viz, {
    req(r$acces)
    r$selected_data <- datalibaba::importer_data(table = r$table, schema = r$schema, db = r$base, user = r$role)
    r$data_csv <- sf::st_drop_geometry(r$selected_data)
    r$nom_csv <- paste(r$base, r$schema, r$table, Sys.Date(), sep = ".")
    })

  # Titre des données attributaires
  output$data_table_preview_title <- renderUI({
    if (isTruthy(r$selected_data)) {
      h4("Données attributaires")
    } else {
      return(NULL)  # Vider le titre si les données sont vides
    }
  })

  #Titre de la carte (Aperçu spatial)
  output$map_title <- renderUI({
    if (isTruthy(r$selected_data) && r$isSpatial) {
      h4("Aperçu spatial")
    } else {
      return(NULL)  # Vider le titre si les données spatiales sont vides
    }
  })

  # Mettre à jour l'affichage de la table dans la zone principale de la page
  output$data_table_preview <- DT::renderDataTable({
    validate(
      need(input$schema != "Tous", ""),
      need(input$table != "Toutes", "")
    )
    req(r$selected_data)
    DT::datatable(head(r$data_csv, 100),
                  filter = 'bottom',
                  extensions = 'Buttons',
                  rownames = FALSE,
                  options = list(
                    dom = 'Bfrtip',
                    pageLength = 20,
                    lengthMenu = c(20, 50, 100),
                    language = list(url = 'https://cdn.datatables.net/plug-ins/1.10.21/i18n/French.json'),
                    autoWidth = FALSE,
                    scrollX = TRUE,  # Activer le défilement horizontal
                    buttons = list(
                      list(
                        extend = 'csv',
                        text = 'Télécharger CSV',
                        filename =  r$nom_csv
                      )
                    )
                  )
    )
  })

  # Mettre à jour la viz carto de la table dans la zone principale de la page
  output$map <- renderLeaflet({
    req(r$selected_data)
    message <- NULL
    if (r$isSpatial) {
      if (nrow(r$selected_data) > 10000) {
        # Sélectionner les 10 000 premières lignes pour l'affichage
        data_to_display <- r$selected_data[1:10000, ]
        message <- "Seules les 10 000 premières lignes sont affichées pour optimiser les performances."

      } else {
        # Si la table est petite( nrow < 10000), ne pas simplifier
        data_to_display <- r$selected_data
        message <- NULL  # Aucun message supplémentaire
      }

      # Affichage du message
      output$map_message <- renderUI({
        if (!is.null(message)) {
          div(
            class = "alert alert-info",
            style = "margin-bottom: 15px;",
            message
          )
        } else {
          NULL
        }
      })

      # Rendu de la carte
      mapview(data_to_display, layer.name = "aperçu")@map
    } else {
      # Cas où les données ne sont pas spatiales
      output$map_message <- renderUI({
        div(
          class = "alert alert-warning",
          style = "margin-bottom: 15px;",
          "Les données sélectionnées ne contiennent pas d'informations spatiales."
        )
      })
      return(NULL)
    }
  })
#
  # # Téléchargement des données attributaires au format CSV, géré par DT, a garder pour le projet QGIS
  # output$downloadData <- downloadHandler(
  #   filename = function() {
  #     r$nom_csv
  #   },
  #   content = function(file) {
  #     write.csv2(r$data_csv, file, row.names = FALSE)
  #   },
  #   contentType = "text/csv"
  # )
  }
