#!/usr/bin/env bash
# backup/restore -- put a database back from a backup set
#
# The current database is dumped before anything is imported, so a wrong choice
# is recoverable. The operator must type the domain to confirm.
set -o pipefail
SELF=$(readlink -f "${BASH_SOURCE[0]}")
NV_BASE=$(cd "$(dirname "$SELF")/../../.." && pwd)
export NV_BASE
# shellcheck source=/dev/null
. "$NV_BASE/lib/core/bootstrap.sh"

nv_require_root || exit 1
ui_header "$(t backup_m_restore)"

sets=()
while IFS= read -r d; do [ -n "$d" ] && sets+=("$d"); done < <(
    ls -1d "$NV_BACKUP_ROOT"/*/ 2>/dev/null | sort -r
)
if [ ${#sets[@]} -eq 0 ]; then ui_info "$(t backup_none)"; exit 0; fi

i=0
for s in "${sets[@]}"; do
    i=$((i + 1))
    printf '  %2d) %-24s %s\n' "$i" "$(basename "${s%/}")" "$(du -sh "$s" 2>/dev/null | cut -f1)"
done
printf '  %2d) %s\n' 0 "$(t menu_back)"
ui_blank

printf '  %s: ' "$(t backup_pick_set)"
read -r pick || exit 130
case $pick in ''|*[!0-9]*) ui_err "$(t ui_invalid_number)"; exit 2 ;; esac
[ "$pick" -eq 0 ] && exit 0
[ "$pick" -lt 1 ] || [ "$pick" -gt ${#sets[@]} ] && { ui_err "$(t menu_invalid)"; exit 2; }
set_dir=${sets[$((pick - 1))]}

# which dump inside the set
mapfile -t dumps < <(find "$set_dir" -maxdepth 1 -name '*.sql.gz' -printf '%f\n' 2>/dev/null | sort)
if [ ${#dumps[@]} -eq 0 ]; then ui_err "$(t backup_no_dump)"; exit 1; fi

domains=()
for f in "${dumps[@]}"; do domains+=("${f%.sql.gz}"); done

i=0
printf '\n'
for d in "${domains[@]}"; do
    i=$((i + 1))
    printf '  %2d) %s\n' "$i" "$d"
done
printf '  %2d) %s\n' 0 "$(t menu_back)"
ui_blank

printf '  %s: ' "$(t backup_pick_db)"
read -r dpick || exit 130
case $dpick in ''|*[!0-9]*) ui_err "$(t ui_invalid_number)"; exit 2 ;; esac
[ "$dpick" -eq 0 ] && exit 0
[ "$dpick" -lt 1 ] || [ "$dpick" -gt ${#domains[@]} ] && { ui_err "$(t menu_invalid)"; exit 2; }
domain=${domains[$((dpick - 1))]}
file="$set_dir/$domain.sql.gz"

if nv_site_exists "$domain"; then
    target_db=$(nv_site_get "$domain" db_name "")
else
    printf '  %s [%s]: ' "$(t backup_target_db)" "$domain"
    read -r target_db || exit 130
    target_db=$(nv_trim "$target_db")
fi
nv_valid_dbname "$target_db" || { ui_err "$(t db_bad_name)"; exit 2; }

ui_blank
ui_warn "$(t backup_restore_warn "$target_db")"
ui_confirm_typed "$(t backup_restore_confirm)" "$domain" || { ui_info "$(t pf_cancelled)"; exit 3; }

nv_lock_acquire "db:$target_db" 10 || { nv_fail 6199 "$(t lock_busy "$target_db")"; exit 1; }

ui_step "$(t backup_dump_current)"
safety="$NV_BACKUP_ROOT/$(date -u '+%Y%m%dT%H%M%SZ').pre-restore"
install -d -m 0700 "$safety"
pass=$(nv_secret db_root_password)
if [ -n "$pass" ]; then
    mysqldump --protocol=socket -u root -p"$pass" --single-transaction "$target_db" 2>/dev/null \
        | gzip -9 >"$safety/$target_db.sql.gz" || true
else
    mysqldump --protocol=socket -u root --single-transaction "$target_db" 2>/dev/null \
        | gzip -9 >"$safety/$target_db.sql.gz" || true
fi
ui_ok "$(t backup_safety_at "$safety")"

ui_step "$(t backup_importing "$file")"
if gunzip -c "$file" | mariadb --protocol=socket -u root "$target_db" 2>/dev/null; then
    ui_ok "$(t backup_restore_ok "$target_db")"
    nv_trace backup-restore "$target_db <- $file"
else
    nv_fail 4403 "$(t backup_restore_failed)"
    ui_info "$(t backup_restore_safety "$safety")"
    nv_lock_release "db:$target_db"
    exit 1
fi
nv_lock_release "db:$target_db"
ui_blank
exit 0
