#!/usr/bin/env bash
# Daily backup: SQLite DB + static/images → /root/backups/<instance>/<YYYY-MM-DD>/
# Prune backup folders older than RETENTION_DAYS (default 30).
set -euo pipefail

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

BACKUP_ROOT="${BACKUP_ROOT:-/root/backups}"
RETENTION_DAYS="${RETENTION_DAYS:-30}"
INSTANCE_NAME="${BACKUP_INSTANCE:-$(basename "$PROJECT_DIR")}"
TZ_NAME="${BACKUP_TZ:-Asia/Shanghai}"

log() {
  printf '[%s] %s\n' "$(TZ="$TZ_NAME" date '+%Y-%m-%d %H:%M:%S %Z')" "$*"
}

read_env_var() {
  local key="$1"
  local default="$2"
  local line
  if [[ ! -f .env ]]; then
    printf '%s' "$default"
    return
  fi
  line="$(grep -E "^${key}=" .env 2>/dev/null | tail -1 || true)"
  if [[ -z "$line" ]]; then
    printf '%s' "$default"
    return
  fi
  printf '%s' "${line#*=}" | tr -d '\r'
}

resolve_project_path() {
  local p="$1"
  if [[ "$p" == /* ]]; then
    printf '%s' "$p"
  else
    printf '%s' "$PROJECT_DIR/$p"
  fi
}

prune_old_backups() {
  local base="$BACKUP_ROOT/$INSTANCE_NAME"
  [[ -d "$base" ]] || return 0
  local cutoff
  cutoff="$(TZ="$TZ_NAME" date -d "-${RETENTION_DAYS} days" +%Y-%m-%d 2>/dev/null || true)"
  if [[ -z "$cutoff" ]]; then
    find "$base" -mindepth 1 -maxdepth 1 -type d -mtime +"$RETENTION_DAYS" -print0 |
      xargs -r -0 rm -rf
    return 0
  fi
  local dir name
  for dir in "$base"/*/; do
    [[ -d "$dir" ]] || continue
    name="$(basename "$dir")"
    [[ "$name" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] || continue
    if [[ "$name" < "$cutoff" ]]; then
      log "prune: remove $dir (older than ${RETENTION_DAYS} days)"
      rm -rf "$dir"
    fi
  done
}

DB_REL="$(read_env_var DB_PATH crypto.db)"
UPLOAD_REL="$(read_env_var UPLOAD_DIR static/images)"
BACKUP_ROOT="$(read_env_var BACKUP_ROOT "$BACKUP_ROOT")"
RETENTION_DAYS="$(read_env_var BACKUP_RETENTION_DAYS "$RETENTION_DAYS")"
INSTANCE_NAME="$(read_env_var BACKUP_INSTANCE "$INSTANCE_NAME")"

DB_PATH="$(resolve_project_path "$DB_REL")"
UPLOAD_DIR="$(resolve_project_path "$UPLOAD_REL")"
DATE_TAG="$(TZ="$TZ_NAME" date +%Y-%m-%d)"
DEST="$BACKUP_ROOT/$INSTANCE_NAME/$DATE_TAG"

if [[ ! -f "$DB_PATH" ]]; then
  log "error: database not found: $DB_PATH"
  exit 1
fi

mkdir -p "$DEST"
log "start backup instance=$INSTANCE_NAME dest=$DEST"

if command -v sqlite3 >/dev/null 2>&1; then
  sqlite3 "$DB_PATH" ".backup '$DEST/crypto.db'"
  log "db: sqlite3 backup -> $DEST/crypto.db"
else
  cp -a "$DB_PATH" "$DEST/crypto.db"
  log "db: cp -> $DEST/crypto.db (sqlite3 not installed)"
fi

if [[ -d "$UPLOAD_DIR" ]]; then
  tar -czf "$DEST/static_images.tar.gz" -C "$(dirname "$UPLOAD_DIR")" "$(basename "$UPLOAD_DIR")"
  log "images: $UPLOAD_DIR -> $DEST/static_images.tar.gz"
else
  log "warn: upload dir missing, skip images: $UPLOAD_DIR"
fi

{
  echo "instance=$INSTANCE_NAME"
  echo "project_dir=$PROJECT_DIR"
  echo "backup_date=$DATE_TAG"
  echo "db_path=$DB_PATH"
  echo "upload_dir=$UPLOAD_DIR"
} >"$DEST/manifest.txt"

prune_old_backups
log "done"
