#!/usr/bin/env bash

dispatcher_prompt_and_run_module() {
  local module_id="$1"
  local target_user=""
  local selected_groups=""
  local ssh_port=""
  local ssh_password_auth=""
  local ssh_root_login=""
  local avahi_enable=""
  local avahi_publish_workstation=""
  local host_name=""
  local domain_name=""
  local iface=""
  local ip_mode=""
  local ip_address=""
  local ip_prefix=""
  local ip_gateway=""
  local ip_dns=""
  local selected_nfs_shares=""
  local share_name=""
  local share_path=""
  local share_user=""
  local share_read_only=""
  local share_public=""
  local archive_name=""
  local docker_data_dir=""
  local default_nfs_ids=""
  local nfs_entry=""
  local nfs_item_id=""
  local nfs_item_name=""
  local nfs_mount_path=""
  local nfs_access=""
  local nfs_enabled=""
  local nfs_item_labels=()
  local nfs_item_ids=()
  local nfs_labels_blob=""
  local default_nfs_indices=""
  local nfs_action=""
  local nfs_mount_now=""
  local nfs_server_mode=""
  local samba_mode=""
  local grub_default_mode=""
  local grub_save_default=""
  local grub_timeout=""
  local grub_timeout_style=""
  local grub_os_prober=""
  local grub_gfxmode=""
  local grub_cmdline=""
  local grub_extra_cmdline=""
  local grub_keep_extra=""
  local grub_selection=""
  local grub_index=1

  case "$module_id" in
    system/user-sudo)
      target_user="$(prompt_read_default "Nom de l'utilisateur a configurer" "${POSTINSTALL_DEFAULT_USER:-gilles}")"
      dispatcher_run_module "$module_id" "$target_user"
      ;;
    system/user-groups)
      target_user="$(prompt_read_default "Nom de l'utilisateur a configurer" "${POSTINSTALL_DEFAULT_USER:-gilles}")"
      selected_groups="$(prompt_read_csv_default "Groupes a ajouter, separes par des virgules" "${POSTINSTALL_USER_GROUPS_DEFAULT_GROUPS:-audio,video,plugdev,dialout,netdev,lpadmin,scanner}")"
      dispatcher_run_module "$module_id" "$target_user" "$selected_groups"
      ;;
    network/ssh-server)
      ssh_port="$(prompt_read_default "Port SSH" "${POSTINSTALL_SSH_PORT:-22}")"
      ssh_password_auth="$(prompt_confirm_default "Autoriser l'authentification par mot de passe" "${POSTINSTALL_SSH_PASSWORD_AUTH:-yes}")"
      ssh_root_login="$(prompt_confirm_default "Autoriser la connexion root SSH" "${POSTINSTALL_SSH_ROOT_LOGIN:-no}")"
      dispatcher_run_module "$module_id" "$ssh_port" "$ssh_password_auth" "$ssh_root_login"
      ;;
    network/mdns-avahi)
      avahi_enable="$(prompt_confirm_default "Activer la publication mDNS de la machine" "${POSTINSTALL_MDNS_AVAHI_ENABLE:-yes}")"
      avahi_publish_workstation="$(prompt_confirm_default "Publier la machine comme poste de travail" "${POSTINSTALL_MDNS_AVAHI_PUBLISH_WORKSTATION:-yes}")"
      dispatcher_run_module "$module_id" "$avahi_enable" "$avahi_publish_workstation"
      ;;
    network/identity)
      host_name="$(prompt_read_default "Hostname" "${POSTINSTALL_NETWORK_IDENTITY_DEFAULT_HOSTNAME:-debian}")"
      domain_name="$(prompt_read_default "Domaine local" "${POSTINSTALL_NETWORK_IDENTITY_DEFAULT_DOMAIN:-local}")"
      dispatcher_run_module "$module_id" "$host_name" "$domain_name"
      ;;
    network/ip-config)
      iface="$(prompt_read_default "Interface reseau" "${POSTINSTALL_NETWORK_IP_DEFAULT_INTERFACE:-$(system_primary_interface)}")"
      ip_mode="$(prompt_read_default "Mode reseau (dhcp ou static)" "${POSTINSTALL_NETWORK_IP_DEFAULT_MODE:-dhcp}")"
      if [[ "$ip_mode" == "static" ]]; then
        ip_address="$(prompt_read_default "Adresse IP" "${POSTINSTALL_NETWORK_IP_DEFAULT_ADDRESS:-10.0.0.10}")"
        ip_prefix="$(prompt_read_default "Prefixe CIDR" "${POSTINSTALL_NETWORK_IP_DEFAULT_PREFIX:-22}")"
        ip_gateway="$(prompt_read_default "Passerelle" "${POSTINSTALL_NETWORK_IP_DEFAULT_GATEWAY:-10.0.0.1}")"
        ip_dns="$(prompt_read_default "DNS" "${POSTINSTALL_NETWORK_IP_DEFAULT_DNS:-10.0.0.1}")"
      else
        ip_address=""
        ip_prefix=""
        ip_gateway=""
        ip_dns=""
      fi
      dispatcher_run_module "$module_id" "$iface" "$ip_mode" "$ip_address" "$ip_prefix" "$ip_gateway" "$ip_dns"
      ;;
    network/nfs-client)
      # shellcheck source=/dev/null
      source "$RUNTIME_PROJECT_ROOT/modules/network/nfs-client/module.sh"
      nfs_action="$(prompt_select_from_list "Action NFS client" "activer des partages" "desactiver des partages")"
      nfs_item_labels=()
      nfs_item_ids=()
      if [[ "$nfs_action" == "desactiver des partages" ]]; then
        ui_section "Partages NFS actifs dans fstab"
        while IFS= read -r nfs_entry; do
          [[ -n "$nfs_entry" ]] || continue
          IFS='|' read -r nfs_item_id nfs_item_name nfs_mount_path nfs_remote nfs_access <<< "$nfs_entry"
          nfs_item_ids+=("$nfs_item_id")
          nfs_item_labels+=("$nfs_item_id : $nfs_item_name -> $nfs_mount_path ($nfs_access)")
        done < <(module_nfs_client_active_entries)
        if [[ "${#nfs_item_ids[@]}" -eq 0 ]]; then
          ui_info "Aucun partage NFS actif a desactiver"
          return 0
        fi
        nfs_labels_blob="$(printf '%s\n' "${nfs_item_labels[@]}")"
        selected_nfs_shares="$(prompt_select_multiple_from_list "Selectionner les partages a retirer de fstab, indexes separes par des virgules" "" "$nfs_labels_blob" "${nfs_item_ids[@]}")"
        dispatcher_run_module "$module_id" "disable" "$selected_nfs_shares"
      else
        ui_section "Partages NFS client disponibles"
        while IFS= read -r nfs_entry; do
          [[ -n "$nfs_entry" ]] || continue
          IFS='|' read -r nfs_item_id nfs_item_name _ _ _ nfs_mount_path nfs_access _ nfs_enabled <<< "$nfs_entry"
          nfs_item_ids+=("$nfs_item_id")
          nfs_item_labels+=("$nfs_item_id : $nfs_item_name -> $nfs_mount_path ($nfs_access)")
        done < <(module_nfs_client_entries)
        default_nfs_indices="$(module_nfs_client_default_indices)"
        nfs_labels_blob="$(printf '%s\n' "${nfs_item_labels[@]}")"
        selected_nfs_shares="$(prompt_select_multiple_from_list "Selectionner les partages a activer dans fstab, indexes separes par des virgules" "$default_nfs_indices" "$nfs_labels_blob" "${nfs_item_ids[@]}")"
        nfs_mount_now="$(prompt_confirm_default "Monter immediatement les partages selectionnes" "yes")"
        dispatcher_run_module "$module_id" "enable" "$selected_nfs_shares" "$nfs_mount_now"
      fi
      ;;
    network/nfs-server)
      nfs_server_mode="$(prompt_select_described_from_list \
        "Mode de synchronisation NFS serveur" \
        "add-only|Ajoute seulement les exports absents sans retirer les autres." \
        "strict|Remplace la zone geree pour refléter exactement le YAML du repo.")"
      ui_info "Synchronisation des exports NFS depuis le fichier YAML du repo"
      dispatcher_run_module "$module_id" "$nfs_server_mode"
      ;;
    network/samba-share)
      samba_mode="$(prompt_select_described_from_list \
        "Mode de synchronisation Samba" \
        "add-only|Ajoute seulement les partages absents sans ecraser le reste." \
        "strict|Regénère la zone geree pour correspondre exactement au YAML du repo.")"
      ui_info "Synchronisation des partages Samba depuis le fichier YAML du repo"
      dispatcher_run_module "$module_id" "$samba_mode"
      ;;
    hardware/detect)
      dispatcher_run_module "$module_id"
      ;;
    boot/grub-theme)
      # shellcheck source=/dev/null
      source "$RUNTIME_PROJECT_ROOT/modules/boot/grub-theme/module.sh"
      mapfile -t grub_archives < <(module_grub_theme_list_archives)
      if [[ "${#grub_archives[@]}" -eq 0 ]]; then
        ui_warn "Aucune archive de theme GRUB disponible"
        return 1
      fi
      ui_section "Themes GRUB disponibles"
      grub_index=1
      for archive_name in "${grub_archives[@]}"; do
        printf ' %d. %s (%s)\n' "$grub_index" "$(module_grub_theme_archive_label "$archive_name")" "$archive_name"
        grub_index=$((grub_index + 1))
      done
      grub_selection="$(prompt_select_number "Selectionner une archive de theme" 1 "${#grub_archives[@]}")"
      archive_name="${grub_archives[$((grub_selection - 1))]}"
      grub_default_mode="$(prompt_select_described_from_list \
        "Mode de demarrage par defaut" \
        "dernier choix|Redemarre sur le dernier systeme choisi au menu GRUB." \
        "toujours Debian|Demarre toujours sur la premiere entree GRUB, en general Debian.")"
      if [[ "$grub_default_mode" == "dernier choix" ]]; then
        grub_default_mode="saved"
      elif [[ "$grub_default_mode" == "toujours Debian" ]]; then
        grub_default_mode="0"
      fi
      grub_save_default="$(prompt_confirm_default "Memoriser le dernier OS choisi au boot" "yes")"
      grub_timeout="$(prompt_read_default "Temps d'attente du menu GRUB" "5")"
      grub_timeout_style="$(prompt_select_described_from_list \
        "Style du menu GRUB" \
        "menu visible|Affiche toujours le menu GRUB pendant le delai choisi." \
        "menu cache|Cache le menu au demarrage sauf cas particulier.")"
      if [[ "$grub_timeout_style" == "menu visible" ]]; then
        grub_timeout_style="menu"
      elif [[ "$grub_timeout_style" == "menu cache" ]]; then
        grub_timeout_style="hidden"
      fi
      grub_os_prober="$(prompt_confirm_default "Activer la detection Windows et autres OS" "yes")"
      if [[ "$grub_os_prober" == "yes" ]]; then
        grub_os_prober="false"
      else
        grub_os_prober="true"
      fi
      grub_gfxmode="$(prompt_read_default "Resolution GRUB (auto, 1920x1080, 2560x1440...)" "auto")"
      grub_cmdline="$(prompt_read_default "Parametres noyau Linux par defaut" "quiet splash")"
      grub_extra_cmdline="$(module_grub_theme_extra_cmdline_options "$grub_cmdline")"
      if [[ -n "$grub_extra_cmdline" ]]; then
        ui_info "Options noyau detectees sur la machine mais absentes de la config saisie : $grub_extra_cmdline"
        grub_keep_extra="$(prompt_confirm_default "Conserver ces options supplementaires" "yes")"
        if [[ "$grub_keep_extra" == "yes" ]]; then
          grub_cmdline="$(module_grub_theme_merge_cmdline_options "$grub_cmdline" "$grub_extra_cmdline")"
        fi
      fi
      dispatcher_run_module "$module_id" "$archive_name" "$grub_default_mode" "$grub_save_default" "$grub_timeout" "$grub_timeout_style" "$grub_os_prober" "$grub_gfxmode" "$grub_cmdline"
      ;;
    containers/docker-engine)
      target_user="$(prompt_read_default "Utilisateur a ajouter au groupe docker" "${POSTINSTALL_DOCKER_TARGET_USER:-gilles}")"
      docker_data_dir="$(prompt_read_default "Dossier Docker" "/home/${target_user}/docker")"
      dispatcher_run_module "$module_id" "$target_user" "$docker_data_dir"
      ;;
    *)
      dispatcher_run_module "$module_id"
      ;;
  esac
}

dispatcher_run_module() {
  local module_id="$1"
  local module_path=""
  local module_slug=""
  local install_function=""

  shift

  if ! registry_has_module "$module_id"; then
    ui_error "Module introuvable : $module_id"
    return 1
  fi

  module_path="$(registry_module_path "$module_id")"
  # shellcheck source=/dev/null
  source "$module_path"

  module_slug="${module_id##*/}"
  module_slug="${module_slug//-/_}"
  install_function="module_${module_slug}_install"

  if ! declare -F "$install_function" >/dev/null 2>&1; then
    ui_error "Fonction d'installation absente pour le module : $module_id"
    return 1
  fi

  ui_section "Execution du module $module_id"
  "$install_function" "$@"
}

dispatcher_not_implemented() {
  local feature="$1"
  ui_warn "Fonction non implementee : $feature"
}
