#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=/dev/null
source "$SCRIPT_DIR/libenv.sh"

log() { printf '[limristem-mail-restore] %s\n' "$*"; }

usage() {
  cat <<'EOF'
Uso:
  restore.sh --source /var/backups/limristem-mail/<backup-dir> [--target-root /] [--restore-files] [--restore-db]

Note:
  - Il restore filesystem di backup incrementali richiede l'applicazione della catena completa (full + incrementali successivi).
  - I backup MariaDB fisici vengono solo estratti/stage-ati: la copy-back finale richiede un intervento controllato.
  - Il restore DB richiede privilegi DDL (DROP/CREATE): usa MariaDB root via socket locale o LIMRISTEM_MAIL_DB_ROOT_PASS.
EOF
}

require_root() {
  if [[ $EUID -ne 0 ]]; then
    log "Questo script va eseguito come root."
    exit 1
  fi
}

load_env() {
  limristem_mail_load_env_file "$LIMRISTEM_MAIL_CONFIG_DIR/limristem-mail.env"
}

mysql_client_cmd() {
  if command -v mariadb >/dev/null 2>&1; then
    printf 'mariadb\n'
  else
    printf 'mysql\n'
  fi
}

# Elevated DB client for logical restore (needs DROP/CREATE). Prefer local root socket.
mysql_restore_cmd() {
  local mysql_cmd
  mysql_cmd=$(mysql_client_cmd)
  local db_name=${LIMRISTEM_MAIL_DB_NAME:-limristem-mail}

  # 1) Local unix socket as root without password (default Debian/MariaDB root)
  if "$mysql_cmd" -uroot --protocol=socket "$db_name" -e "SELECT 1" >/dev/null 2>&1; then
    printf '%s\n' "$mysql_cmd -uroot --protocol=socket"
    return 0
  fi
  # 2) Explicit root password
  if [[ -n "${LIMRISTEM_MAIL_DB_ROOT_PASS:-}" ]]; then
    if MYSQL_PWD="$LIMRISTEM_MAIL_DB_ROOT_PASS" "$mysql_cmd" -h"${LIMRISTEM_MAIL_DB_HOST:-127.0.0.1}" -P"${LIMRISTEM_MAIL_DB_PORT:-3306}" -uroot "$db_name" -e "SELECT 1" >/dev/null 2>&1; then
      printf 'MYSQL_PWD=%q %s -h%q -P%q -uroot\n' \
        "$LIMRISTEM_MAIL_DB_ROOT_PASS" "$mysql_cmd" \
        "${LIMRISTEM_MAIL_DB_HOST:-127.0.0.1}" \
        "${LIMRISTEM_MAIL_DB_PORT:-3306}"
      # Can't easily return env+cmd with quoting for eval - use function instead
      return 2
    fi
  fi
  return 1
}

run_mysql_restore() {
  local mysql_cmd db_name host port
  mysql_cmd=$(mysql_client_cmd)
  db_name=${LIMRISTEM_MAIL_DB_NAME:-limristem-mail}
  host=${LIMRISTEM_MAIL_DB_HOST:-127.0.0.1}
  port=${LIMRISTEM_MAIL_DB_PORT:-3306}

  if "$mysql_cmd" -uroot --protocol=socket "$db_name" -e "SELECT 1" >/dev/null 2>&1; then
    log "Restore DB con MariaDB root (unix socket)"
    if [[ "$1" == "--gzip" ]]; then
      gunzip -c "$2" | "$mysql_cmd" -uroot --protocol=socket "$db_name"
    else
      "$mysql_cmd" -uroot --protocol=socket "$db_name" < "$2"
    fi
    return 0
  fi

  if [[ -n "${LIMRISTEM_MAIL_DB_ROOT_PASS:-}" ]]; then
    log "Restore DB con MariaDB root (password da LIMRISTEM_MAIL_DB_ROOT_PASS)"
    if [[ "$1" == "--gzip" ]]; then
      gunzip -c "$2" | MYSQL_PWD="$LIMRISTEM_MAIL_DB_ROOT_PASS" "$mysql_cmd" -h"$host" -P"$port" -uroot "$db_name"
    else
      MYSQL_PWD="$LIMRISTEM_MAIL_DB_ROOT_PASS" "$mysql_cmd" -h"$host" -P"$port" -uroot "$db_name" < "$2"
    fi
    return 0
  fi

  log "ERRORE: restore logico richiede privilegi DDL (DROP/CREATE)."
  log "Configura accesso root locale (socket) oppure limristem_mail_env LIMRISTEM_MAIL_DB_ROOT_PASS."
  log "L'utente applicativo (${LIMRISTEM_MAIL_DB_USER:-app}) ha solo SELECT/INSERT/UPDATE/DELETE e non può ripristinare lo schema."
  return 1
}

SOURCE_DIR=''
TARGET_ROOT='/'
RESTORE_FILES=false
RESTORE_DB=false

while [[ $# -gt 0 ]]; do
  case "$1" in
    --source)
      SOURCE_DIR=$2
      shift 2
      ;;
    --target-root)
      TARGET_ROOT=$2
      shift 2
      ;;
    --restore-files)
      RESTORE_FILES=true
      shift
      ;;
    --restore-db)
      RESTORE_DB=true
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      log "Argomento non riconosciuto: $1"
      usage
      exit 1
      ;;
  esac
done

main() {
  require_root
  load_env

  if [[ -z "$SOURCE_DIR" || ! -d "$SOURCE_DIR" ]]; then
    log "Specifica una directory backup valida con --source."
    exit 1
  fi

  if [[ "$RESTORE_FILES" != true && "$RESTORE_DB" != true ]]; then
    log "Seleziona almeno una tra --restore-files e --restore-db."
    exit 1
  fi

  if [[ "$RESTORE_FILES" == true ]]; then
    local fs_archive
    fs_archive=$(find "$SOURCE_DIR" -maxdepth 1 -type f -name 'filesystem.*.tar*' | sort | head -n 1)
    if [[ -z "$fs_archive" ]]; then
      log "Archivio filesystem non trovato in $SOURCE_DIR"
      exit 1
    fi
    mkdir -p "$TARGET_ROOT"
    log "Ripristino filesystem da ${fs_archive} verso ${TARGET_ROOT}"
    tar --extract --auto-compress --listed-incremental=/dev/null --file="$fs_archive" --directory="$TARGET_ROOT"
  fi

  if [[ "$RESTORE_DB" == true ]]; then
    local logical_dump physical_dir
    logical_dump=$(find "$SOURCE_DIR" -maxdepth 1 -type f -name 'mariadb.logical.sql*' | sort | head -n 1)
    physical_dir=$(find "$SOURCE_DIR" -maxdepth 1 -type d -name 'mariadb.physical' | sort | head -n 1)

    if [[ -n "$logical_dump" ]]; then
      log "Ripristino dump logico ${logical_dump}"
      if [[ "$logical_dump" == *.gz ]]; then
        run_mysql_restore --gzip "$logical_dump"
      else
        run_mysql_restore --file "$logical_dump"
      fi
    elif [[ -n "$physical_dir" ]]; then
      log "Backup MariaDB fisico rilevato in ${physical_dir}"
      log "Esegui manualmente 'mariabackup --prepare --target-dir=${physical_dir}' e la successiva copy-back in una finestra controllata."
    else
      log "Nessun backup database trovato in $SOURCE_DIR"
      exit 1
    fi
  fi

  log "Restore completato."
}

main "$@"
