#!/usr/bin/env bash
#
# restore.sh
# ----------
# Restore the Africa Alert PWA SQLite database from a backup file.
#
# This is a DESTRUCTIVE operation: it overwrites the live database
# (and its WAL/SHM sidecars) with the contents of the backup file.
# The server MUST be stopped before running this, otherwise the running
# Node process will keep writing to the old (now-orphaned) inode and
# any new writes will be lost on restart.
#
# Usage:
#   DB_PATH=/opt/africa-alert/server/data/school.db \
#     ./restore.sh /backups/school-20260716-120000.db
#
# This script is meant to be run on the production Ubuntu 22.04 host.
# It is NOT a Windows script. On a Windows dev box, only
# `bash -n restore.sh` (syntax check) is meaningful.

set -eu

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"

DB_PATH="${DB_PATH:-/opt/africa-alert/server/data/school.db}"
LOG_DIR="${LOG_DIR:-${PROJECT_ROOT}/logs}"
LOG_FILE="${LOG_DIR}/backup.log"

# --- Pre-flight --------------------------------------------------------------

if [ $# -lt 1 ]; then
  echo "usage: $0 <backup-file>" >&2
  echo "  e.g. $0 /backups/school-20260716-120000.db" >&2
  exit 64
fi

BACKUP_FILE="$1"

log() {
  local msg="[$(date -u +%Y-%m-%dT%H:%M:%SZ)] [restore] $*"
  echo "${msg}" | tee -a "${LOG_FILE}" >&2
}

if [ ! -f "${BACKUP_FILE}" ]; then
  log "ERROR: backup file not found: ${BACKUP_FILE}"
  exit 1
fi

if [ ! -s "${BACKUP_FILE}" ]; then
  log "ERROR: backup file is empty: ${BACKUP_FILE}"
  exit 1
fi

# Make sure the destination's parent directory exists; in production this
# is /opt/africa-alert/server/data which the installer already created,
# but a custom DB_PATH may need a parent.
DB_PARENT="$(dirname "${DB_PATH}")"
if [ ! -d "${DB_PARENT}" ]; then
  log "ERROR: DB_PATH parent directory does not exist: ${DB_PARENT}"
  exit 1
fi

# --- Confirmation prompt -----------------------------------------------------
# Non-interactive host (e.g. piped from cron or CI) must explicitly
# opt in with RESTORE_CONFIRM=yes. Otherwise we require a human
# y/N at a TTY to prevent accidental overwrites.
if [ -t 0 ]; then
  echo "============================================================"
  echo "  AFRICA ALERT — DATABASE RESTORE (DESTRUCTIVE)"
  echo "============================================================"
  echo "  Backup file : ${BACKUP_FILE}  ($(stat -c %s "${BACKUP_FILE}") bytes)"
  echo "  Live DB     : ${DB_PATH}"
  echo "  Sidecars    : ${DB_PATH}-wal  ${DB_PATH}-shm  (will be overwritten too)"
  echo "============================================================"
  printf "Type 'yes' to overwrite the live database: "
  read -r CONFIRM
else
  if [ "${RESTORE_CONFIRM:-}" != "yes" ]; then
    log "ERROR: refusing to restore non-interactively without RESTORE_CONFIRM=yes"
    exit 1
  fi
  CONFIRM="yes"
fi

if [ "${CONFIRM}" != "yes" ]; then
  log "aborted by operator (confirmation not 'yes')"
  exit 1
fi

# --- Stop the server if we can ----------------------------------------------
# Best-effort: if systemctl is present, stop the service so the running
# Node process releases its file handles. If the operator already stopped
# it manually, this is a no-op.
if command -v systemctl >/dev/null 2>&1; then
  if systemctl list-unit-files 2>/dev/null | grep -q '^africa-alert\.service'; then
    log "stopping africa-alert service via systemctl"
    systemctl stop africa-alert.service || true
  fi
fi

# --- Snapshot the pre-restore DB to a safe name ------------------------------
# If something goes wrong mid-restore, we want a "before" copy on disk so
# the operator can attempt a manual recovery. This is best-effort; if it
# fails we log and continue (the operator can re-run the backup cron to
# make a fresh safety net).
if [ -f "${DB_PATH}" ]; then
  SAFETY="${DB_PATH}.pre-restore-$(date +%Y%m%d-%H%M%S)"
  if cp -p "${DB_PATH}" "${SAFETY}" 2>/dev/null; then
    log "safety snapshot: ${SAFETY}"
  else
    log "WARN: could not write safety snapshot; continuing anyway"
  fi
fi

# --- Overwrite ---------------------------------------------------------------
# IMPORTANT: SQLite WAL mode keeps -wal and -shm sidecars alongside the
# main .db file. If the backup was taken while the DB was busy, the
# snapshot includes those sidecars (the backup script copies them too).
# If those sidecars exist next to the backup, copy them over the live
# sidecars. If not, the live sidecars must be REMOVED, otherwise SQLite
# on next open will replay stale WAL frames from before the restore
# and silently corrupt the freshly-restored database.
log "restoring ${BACKUP_FILE} -> ${DB_PATH}"
cp -f "${BACKUP_FILE}" "${DB_PATH}"

for ext in wal shm; do
  if [ -f "${BACKUP_FILE}-${ext}" ]; then
    cp -f "${BACKUP_FILE}-${ext}" "${DB_PATH}-${ext}"
    log "restored sidecar ${DB_PATH}-${ext}"
  else
    # Backup has no sidecar (idle-time snapshot) — drop any stale one
    # on the live DB so SQLite does not replay pre-restore frames.
    if [ -f "${DB_PATH}-${ext}" ]; then
      rm -f "${DB_PATH}-${ext}"
      log "removed stale live sidecar ${DB_PATH}-${ext} (no matching backup sidecar)"
    fi
  fi
done

# --- Restart the server if we stopped it ------------------------------------
if command -v systemctl >/dev/null 2>&1; then
  if systemctl list-unit-files 2>/dev/null | grep -q '^africa-alert\.service'; then
    log "starting africa-alert service via systemctl"
    systemctl start africa-alert.service || true
  fi
fi

log "restore complete. next step: run ./verify-restore.sh <backup-file>"
exit 0
