#!/usr/bin/env bash
# wakelai-backup — disaster-recovery backup for the wakelai.com platform.
#
# Produces two downloadable bundles under /var/backups/wakelai:
#   wakelai-core-<ts>.tar.gz    (daily)  code is pushed to GitHub +
#                                         DB dump + .runtime modules + secrets
#                                         + nginx vhosts + ops scripts. A few MB.
#   wakelai-full-<ts>.tar.gz    (weekly) everything in core PLUS every Hermes
#                                         agent-memory volume (~3.5 GB).
#
# Restore with wakelai-restore.sh (see DISASTER_RECOVERY.md).
#
# Usage:
#   wakelai-backup.sh            core backup; auto-upgrades to full on Sunday
#   wakelai-backup.sh --full     force a full backup (includes volumes)
#   wakelai-backup.sh --core     force core only (never volumes)
#   wakelai-backup.sh --no-push  skip the git push step
set -uo pipefail

# ---- config -----------------------------------------------------------------
REPO="/home/ashraffarid2010/wakelai.com"
BACKUP_ROOT="/var/backups/wakelai"
PG_CONTAINER="wakelaicom-postgres"
PG_USER="wakelai"
PG_DB="wakelai"
PG_HOST="127.0.0.1"   # host-networked postgres listens here
PG_PORT="55433"
GIT_REMOTE="origin"
GIT_BRANCH="master"
KEEP_CORE=7      # keep this many core bundles
KEEP_FULL=4      # keep this many full bundles
AUTO_COMMIT=1    # commit uncommitted working-tree changes before pushing
# -----------------------------------------------------------------------------

MODE="auto"; DO_PUSH=1
for a in "$@"; do
  case "$a" in
    --full) MODE="full" ;;
    --core) MODE="core" ;;
    --no-push) DO_PUSH=0 ;;
    *) echo "unknown arg: $a" >&2; exit 2 ;;
  esac
done
# On the auto path, Sunday (day 7) gets a full backup, other days core.
[[ "$MODE" == "auto" ]] && { [[ "$(date +%u)" == "7" ]] && MODE="full" || MODE="core"; }

TS="$(date -u +%Y%m%d-%H%M%S)"
LOG="$BACKUP_ROOT/backup.log"
mkdir -p "$BACKUP_ROOT"
log() { echo "$(date -u '+%F %T') $*" | tee -a "$LOG"; }
WORK="$(mktemp -d /tmp/wakelai-backup.XXXXXX)"
trap 'rm -rf "$WORK"' EXIT

log "=== backup start (mode=$MODE, ts=$TS) ==="

# ---- 1. code -> GitHub ------------------------------------------------------
if [[ "$DO_PUSH" == "1" ]]; then
  if git -C "$REPO" remote get-url "$GIT_REMOTE" >/dev/null 2>&1; then
    if [[ "$AUTO_COMMIT" == "1" && -n "$(git -C "$REPO" status --porcelain)" ]]; then
      git -C "$REPO" add -A
      git -C "$REPO" -c user.name="wakelai-backup" -c user.email="backup@wakelai.com" \
        commit -q -m "chore(backup): snapshot $TS" && log "committed working-tree snapshot"
    fi
    if git -C "$REPO" push -q "$GIT_REMOTE" "$GIT_BRANCH" 2>>"$LOG"; then
      log "git push OK -> $GIT_REMOTE/$GIT_BRANCH"
    else
      log "WARNING: git push failed (see log) — continuing with local bundle"
    fi
  else
    log "WARNING: git remote '$GIT_REMOTE' not configured — skipping code push"
  fi
fi

# ---- 2. staging tree --------------------------------------------------------
STAGE="$WORK/wakelai-$MODE-$TS"
mkdir -p "$STAGE"/{db,config,runtime,nginx,ops,meta}

# ---- 3. database dump -------------------------------------------------------
if docker inspect "$PG_CONTAINER" >/dev/null 2>&1; then
  if docker exec "$PG_CONTAINER" pg_dump -U "$PG_USER" -d "$PG_DB" -h "$PG_HOST" -p "$PG_PORT" \
       --no-owner --clean --if-exists 2>>"$LOG" | gzip > "$STAGE/db/$PG_DB.sql.gz"; then
    sz=$(du -h "$STAGE/db/$PG_DB.sql.gz" | cut -f1)
    log "DB dump OK ($sz)"
  else
    log "ERROR: DB dump failed"
  fi
else
  log "ERROR: postgres container '$PG_CONTAINER' not found — DB NOT backed up"
fi

# ---- 4. config + secrets ----------------------------------------------------
for f in .env .env.local .env.example docker-compose.yml docker-compose.local.yml \
         docker-compose.wakelai.yml prisma/schema.prisma; do
  [[ -f "$REPO/$f" ]] && { mkdir -p "$STAGE/config/$(dirname "$f")"; cp -a "$REPO/$f" "$STAGE/config/$f"; }
done
log "config + secrets captured"

# ---- 5. runtime modules (per-tenant compose / traefik / configs) ------------
if [[ -d "$REPO/.runtime" ]]; then
  tar -C "$REPO" -czf "$STAGE/runtime/runtime.tar.gz" \
      --exclude='*.log' .runtime 2>>"$LOG" && log ".runtime modules captured"
fi

# ---- 6. nginx vhosts (wakelai only) + main config ---------------------------
cp -a /etc/nginx/nginx.conf "$STAGE/nginx/" 2>/dev/null
shopt -s nullglob
for v in /etc/nginx/conf.d/00-wakelai.com.conf \
         /etc/nginx/conf.d/99-wakelai-instances-https.conf \
         /etc/nginx/conf.d/instance-*.conf \
         /etc/nginx/conf.d/*.wakelai.com.conf; do
  cp -a "$v" "$STAGE/nginx/" 2>/dev/null
done
shopt -u nullglob
log "nginx vhosts captured ($(ls "$STAGE/nginx" | wc -l) files)"

# ---- 7. ops scripts + systemd units (self-contained recovery tooling) -------
cp -a "$REPO/ops/." "$STAGE/ops/" 2>/dev/null
for u in wakelai-nextjs.service wakelai-watchdog.service wakelai-watchdog.timer \
         wakelai-backup.service wakelai-backup.timer; do
  cp -a "/etc/systemd/system/$u" "$STAGE/ops/systemd/" 2>/dev/null
done
cp -a /usr/local/bin/wakelai-watchdog.sh "$STAGE/ops/" 2>/dev/null
log "ops tooling captured"

# ---- 8. volumes (full mode only) --------------------------------------------
if [[ "$MODE" == "full" ]]; then
  mkdir -p "$STAGE/volumes"
  vols=$(docker volume ls --format '{{.Name}}' | grep -E 'hermes.*data$|^wakelaicom_(postgres|redis)')
  n=0
  for vol in $vols; do
    if docker run --rm -v "$vol":/src:ro -v "$STAGE/volumes":/dst alpine \
         tar -C /src -czf "/dst/$vol.tar.gz" . 2>>"$LOG"; then
      n=$((n+1))
    else
      log "WARNING: volume backup failed: $vol"
    fi
  done
  log "volumes captured ($n archives, $(du -sh "$STAGE/volumes" | cut -f1))"
fi

# ---- 9. manifest ------------------------------------------------------------
{
  echo "wakelai backup"
  echo "timestamp_utc: $TS"
  echo "mode: $MODE"
  echo "host: $(hostname)"
  echo "git_commit: $(git -C "$REPO" rev-parse HEAD 2>/dev/null)"
  echo "git_remote: $(git -C "$REPO" remote get-url "$GIT_REMOTE" 2>/dev/null)"
  echo "db_users: $(docker exec "$PG_CONTAINER" psql -U "$PG_USER" -d "$PG_DB" -h "$PG_HOST" -p "$PG_PORT" -Atc 'select count(*) from users' 2>/dev/null)"
  echo "db_instances: $(docker exec "$PG_CONTAINER" psql -U "$PG_USER" -d "$PG_DB" -h "$PG_HOST" -p "$PG_PORT" -Atc 'select count(*) from instances' 2>/dev/null)"
} > "$STAGE/meta/manifest.txt"

# ---- 10. bundle + prune -----------------------------------------------------
BUNDLE="$BACKUP_ROOT/wakelai-$MODE-$TS.tar.gz"
tar -C "$WORK" -czf "$BUNDLE" "$(basename "$STAGE")" 2>>"$LOG"
chmod 600 "$BUNDLE"
log "bundle written: $BUNDLE ($(du -h "$BUNDLE" | cut -f1))"

prune() { ls -1t "$BACKUP_ROOT"/wakelai-"$1"-*.tar.gz 2>/dev/null | tail -n +"$(($2+1))" | while read -r old; do rm -f "$old"; log "pruned old: $(basename "$old")"; done; }
prune core "$KEEP_CORE"
prune full "$KEEP_FULL"

log "=== backup done ($BUNDLE) ==="
echo "$BUNDLE"
