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

MODE="${1:-}"
TARGET="${2:-}"
DEFAULT_ROOT="${SORIA_BACKUP_ROOT:-/var/backups/soria-network}"

usage() {
  cat <<'EOF'
Usage:
  sudo ./module5c-config-backup.sh snapshot [backup-root]
  sudo ./module5c-config-backup.sh verify <snapshot-directory>

The snapshot is read-only. It stores sanitized configuration copies, operational
evidence, a manifest and checksums. It never writes configuration back to /etc.
Secret redaction is best-effort and must be reviewed before external transfer.
EOF
}

require_root_for_snapshot() {
  if [[ ${EUID} -ne 0 ]]; then
    echo "Le mode snapshot doit être exécuté avec sudo." >&2
    exit 1
  fi
}

redact_stream() {
  sed -E \
    -e 's/^([[:space:]]*(PrivateKey|PresharedKey|auth_pass|password|enable password|secret|community)[[:space:]=]+).*/\1<REDACTED>/I' \
    -e 's/((token|api[_-]?key)[[:space:]]*[=:][[:space:]]*)[^[:space:]]+/\1<REDACTED>/Ig'
}

safe_copy() {
  local src="$1" snapshot="$2" dest tmp
  [[ -f "$src" ]] || return 0
  dest="${snapshot}/configs${src}"
  tmp="${dest}.tmp"
  mkdir -p "$(dirname "$dest")"
  redact_stream < "$src" > "$tmp"
  chmod 600 "$tmp"
  mv "$tmp" "$dest"
}

capture() {
  local snapshot="$1" rel="$2"
  shift 2
  local dest="${snapshot}/evidence/${rel}" tmp="${snapshot}/evidence/${rel}.tmp"
  mkdir -p "$(dirname "$dest")"
  if command -v "$1" >/dev/null 2>&1; then
    "$@" > "$tmp" 2>&1 || true
  else
    printf 'Commande absente : %s\n' "$1" > "$tmp"
  fi
  redact_stream < "$tmp" > "$dest"
  rm -f "$tmp"
  chmod 600 "$dest"
}

write_manifest() {
  local snapshot="$1"
  {
    echo "snapshot_id=$(basename "$snapshot")"
    echo "created_at=$(date -Is)"
    echo "hostname=$(hostname -f 2>/dev/null || hostname)"
    echo "kernel=$(uname -srmo)"
    echo "redaction=best-effort"
    echo "restore_policy=manual-review-only"
    echo "included_scope=configurations-sanitized,operational-evidence,checksums"
    echo "excluded_scope=private-keys,unredacted-secrets,automatic-restore"
  } > "${snapshot}/MANIFEST.txt"
  chmod 600 "${snapshot}/MANIFEST.txt"
}

snapshot() {
  require_root_for_snapshot
  local root="${TARGET:-$DEFAULT_ROOT}"
  local stamp host dir archive
  stamp="$(date -u +%Y%m%dT%H%M%SZ)"
  host="$(hostname -s 2>/dev/null || echo node)"
  dir="${root}/${host}-${stamp}"
  archive="${dir}.tar.gz"

  umask 077
  mkdir -p "$dir/configs" "$dir/evidence"
  write_manifest "$dir"

  shopt -s nullglob
  local files=(
    /etc/network/interfaces
    /etc/netplan/*.yaml
    /etc/nftables.conf
    /etc/frr/frr.conf
    /etc/frr/daemons
    /etc/keepalived/keepalived.conf
    /etc/wireguard/*.conf
    /etc/ssh/sshd_config
    /etc/ssh/sshd_config.d/*.conf
    /etc/prometheus/prometheus.yml
    /etc/prometheus/rules/*.yml
    /etc/prometheus/rules/*.yaml
  )
  local src
  for src in "${files[@]}"; do
    safe_copy "$src" "$dir"
  done

  capture "$dir" ip-address.txt ip -details address show
  capture "$dir" ip-route-all.txt ip route show table all
  capture "$dir" ip-rule.txt ip rule show
  capture "$dir" bridge-vlan.txt bridge vlan show
  capture "$dir" nft-ruleset.txt nft list ruleset
  capture "$dir" wireguard-status.txt wg show
  capture "$dir" sockets.txt ss -lntup
  capture "$dir" frr-running-config.txt vtysh -c "show running-config"
  capture "$dir" frr-ospf-neighbors.txt vtysh -c "show ip ospf neighbor"
  capture "$dir" services.txt systemctl --no-pager --type=service --state=running

  {
    for cmd in ip nft wg vtysh keepalived prometheus promtool node_exporter; do
      if command -v "$cmd" >/dev/null 2>&1; then
        printf '\n[%s]\n' "$cmd"
        "$cmd" --version 2>&1 | head -n 3 || true
      fi
    done
  } | redact_stream > "$dir/evidence/tool-versions.txt"
  chmod 600 "$dir/evidence/tool-versions.txt"

  (
    cd "$dir"
    find . -type f ! -name SHA256SUMS -print0 \
      | sort -z \
      | xargs -0 sha256sum > SHA256SUMS
  )
  chmod 600 "$dir/SHA256SUMS"

  tar -czf "$archive" -C "$root" "$(basename "$dir")"
  sha256sum "$archive" > "${archive}.sha256"
  chmod 600 "$archive" "${archive}.sha256"

  echo "Snapshot créé : $dir"
  echo "Archive créée : $archive"
  echo "Révise les fichiers sanitizés avant toute copie externe."
}

verify() {
  local dir="$TARGET"
  [[ -n "$dir" ]] || { echo "Répertoire snapshot requis." >&2; exit 1; }
  [[ -f "$dir/SHA256SUMS" ]] || { echo "SHA256SUMS absent dans $dir." >&2; exit 1; }
  (
    cd "$dir"
    sha256sum -c SHA256SUMS
  )
}

case "$MODE" in
  snapshot) snapshot ;;
  verify) verify ;;
  -h|--help|"") usage ;;
  *) usage; exit 1 ;;
esac
