#!/usr/bin/env bash
# =============================================================================
# Changemaker Lite V2 — Backup Script
# Backs up PostgreSQL databases, uploads, and generates a manifest.
# Usage: ./scripts/backup.sh [--s3] [--retention DAYS]
# =============================================================================
set -euo pipefail

# --- Configuration ---
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
BACKUP_DIR="${BACKUP_DIR:-$PROJECT_DIR/backups}"
RETENTION_DAYS="${RETENTION_DAYS:-30}"
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
BACKUP_NAME="changemaker-v2-backup-${TIMESTAMP}"
BACKUP_PATH="${BACKUP_DIR}/${BACKUP_NAME}"
S3_UPLOAD=false

# --- Parse args ---
while [[ $# -gt 0 ]]; do
  case "$1" in
    --s3) S3_UPLOAD=true; shift ;;
    --retention) RETENTION_DAYS="$2"; shift 2 ;;
    --help)
      echo "Usage: $0 [--s3] [--retention DAYS]"
      echo "  --s3           Upload backup to S3 (requires AWS CLI + S3_BUCKET env var)"
      echo "  --retention N  Delete local backups older than N days (default: 30)"
      exit 0 ;;
    *) echo "Unknown option: $1"; exit 1 ;;
  esac
done

# --- Load .env if present (safe parsing to handle special characters) ---
if [ -f "$PROJECT_DIR/.env" ]; then
  while IFS='=' read -r key value; do
    # Skip comments and empty lines
    [[ -z "$key" || "$key" =~ ^[[:space:]]*# ]] && continue
    # Trim leading/trailing whitespace from key
    key="$(echo "$key" | xargs)"
    # Strip surrounding quotes from value if present
    value="${value%\"}"
    value="${value#\"}"
    value="${value%\'}"
    value="${value#\'}"
    # Only export valid variable names
    if [[ "$key" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
      export "$key=$value"
    fi
  done < "$PROJECT_DIR/.env"
fi

# --- Derived vars ---
PG_CONTAINER="${PG_CONTAINER:-changemaker-v2-postgres}"
PG_USER="${V2_POSTGRES_USER:-changemaker}"
PG_DB="${V2_POSTGRES_DB:-changemaker_v2}"
LISTMONK_PG_CONTAINER="${LISTMONK_PG_CONTAINER:-listmonk-db}"
LISTMONK_PG_USER="${LISTMONK_DB_USER:-listmonk}"
LISTMONK_PG_DB="${LISTMONK_DB_NAME:-listmonk}"
UPLOADS_DIR="${PROJECT_DIR}/assets/uploads"

echo "=========================================="
echo "  Changemaker Lite V2 — Backup"
echo "  ${TIMESTAMP}"
echo "=========================================="
echo ""

# --- Create backup directory ---
mkdir -p "$BACKUP_PATH"

# --- 1. V2 PostgreSQL Dump ---
echo "[1/4] Dumping V2 PostgreSQL (${PG_DB})..."
if docker ps --format '{{.Names}}' | grep -q "^${PG_CONTAINER}$"; then
  docker exec "$PG_CONTAINER" pg_dump -U "$PG_USER" -d "$PG_DB" --no-owner --no-acl \
    | gzip > "${BACKUP_PATH}/v2-postgres.sql.gz"
  echo "  -> v2-postgres.sql.gz ($(du -h "${BACKUP_PATH}/v2-postgres.sql.gz" | cut -f1))"
else
  echo "  [WARN] Container ${PG_CONTAINER} not running, skipping V2 DB dump."
fi

# --- 1b. Gancio PostgreSQL Dump (shared PostgreSQL, separate database) ---
echo "[1b/4] Dumping Gancio PostgreSQL (gancio)..."
if docker ps --format '{{.Names}}' | grep -q "^${PG_CONTAINER}$"; then
  docker exec "$PG_CONTAINER" pg_dump -U "$PG_USER" -d gancio --no-owner --no-acl \
    | gzip > "${BACKUP_PATH}/gancio-postgres.sql.gz" 2>/dev/null \
    && echo "  -> gancio-postgres.sql.gz ($(du -h "${BACKUP_PATH}/gancio-postgres.sql.gz" | cut -f1))" \
    || echo "  [INFO] Gancio database not found, skipping."
else
  echo "  [INFO] V2 PostgreSQL not running, skipping Gancio dump."
fi

# --- 2. Listmonk PostgreSQL Dump (optional) ---
echo "[2/4] Dumping Listmonk PostgreSQL (${LISTMONK_PG_DB})..."
if docker ps --format '{{.Names}}' | grep -q "^${LISTMONK_PG_CONTAINER}$"; then
  docker exec "$LISTMONK_PG_CONTAINER" pg_dump -U "$LISTMONK_PG_USER" -d "$LISTMONK_PG_DB" --no-owner --no-acl \
    | gzip > "${BACKUP_PATH}/listmonk-postgres.sql.gz"
  echo "  -> listmonk-postgres.sql.gz ($(du -h "${BACKUP_PATH}/listmonk-postgres.sql.gz" | cut -f1))"
else
  echo "  [WARN] Container ${LISTMONK_PG_CONTAINER} not running, skipping Listmonk dump."
fi

# --- 3. Uploads Archive ---
echo "[3/4] Archiving uploads..."
if [ -d "$UPLOADS_DIR" ] && [ "$(ls -A "$UPLOADS_DIR" 2>/dev/null)" ]; then
  tar -czf "${BACKUP_PATH}/uploads.tar.gz" -C "$(dirname "$UPLOADS_DIR")" "$(basename "$UPLOADS_DIR")"
  echo "  -> uploads.tar.gz ($(du -h "${BACKUP_PATH}/uploads.tar.gz" | cut -f1))"
else
  echo "  [INFO] No uploads directory or empty, skipping."
fi

# --- 4. Manifest ---
echo "[4/4] Generating manifest..."
MANIFEST_FILE="${BACKUP_PATH}/manifest.json"
{
  echo "{"
  echo "  \"timestamp\": \"${TIMESTAMP}\","
  echo "  \"backup_name\": \"${BACKUP_NAME}\","
  echo "  \"files\": ["

  FIRST=true
  for f in "${BACKUP_PATH}"/*.{sql.gz,tar.gz}; do
    [ -f "$f" ] || continue
    SIZE="$(stat --printf='%s' "$f" 2>/dev/null || stat -f '%z' "$f" 2>/dev/null || echo 0)"
    SHA256="$(sha256sum "$f" 2>/dev/null | cut -d' ' -f1 || shasum -a 256 "$f" | cut -d' ' -f1)"
    BASENAME="$(basename "$f")"
    if [ "$FIRST" = true ]; then
      FIRST=false
    else
      echo ","
    fi
    printf '    {"file": "%s", "size_bytes": %s, "sha256": "%s"}' "$BASENAME" "$SIZE" "$SHA256"
  done

  echo ""
  echo "  ],"
  echo "  \"v2_database\": \"${PG_DB}\","
  echo "  \"listmonk_database\": \"${LISTMONK_PG_DB}\","
  echo "  \"retention_days\": ${RETENTION_DAYS}"
  echo "}"
} > "$MANIFEST_FILE"

echo "  -> manifest.json"
echo ""

# --- Create single archive ---
ARCHIVE_FILE="${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
tar -czf "$ARCHIVE_FILE" -C "$BACKUP_DIR" "$BACKUP_NAME"
rm -rf "$BACKUP_PATH"
echo "Archive: ${ARCHIVE_FILE} ($(du -h "$ARCHIVE_FILE" | cut -f1))"
echo ""

# --- Optional S3 Upload ---
if [ "$S3_UPLOAD" = true ]; then
  S3_BUCKET="${S3_BUCKET:-}"
  S3_PREFIX="${S3_PREFIX:-changemaker-backups}"
  if [ -z "$S3_BUCKET" ]; then
    echo "[WARN] S3_BUCKET not set, skipping S3 upload."
  elif ! command -v aws &>/dev/null; then
    echo "[WARN] AWS CLI not found, skipping S3 upload."
  else
    echo "Uploading to s3://${S3_BUCKET}/${S3_PREFIX}/${BACKUP_NAME}.tar.gz..."
    aws s3 cp "$ARCHIVE_FILE" "s3://${S3_BUCKET}/${S3_PREFIX}/${BACKUP_NAME}.tar.gz"
    echo "S3 upload complete."
  fi
  echo ""
fi

# --- Retention Cleanup ---
echo "Cleaning up backups older than ${RETENTION_DAYS} days..."
DELETED=0
for old in "${BACKUP_DIR}"/changemaker-v2-backup-*.tar.gz; do
  [ -f "$old" ] || continue
  if [ "$(find "$old" -mtime +"$RETENTION_DAYS" -print 2>/dev/null)" ]; then
    rm -f "$old"
    DELETED=$((DELETED + 1))
  fi
done
echo "  Deleted ${DELETED} old backup(s)."
echo ""

# --- Push metrics to Bunker Ops (if enabled) ---
if [ "${BUNKER_OPS_ENABLED:-false}" = "true" ] && [ -n "${BUNKER_OPS_REMOTE_WRITE_URL:-}" ]; then
  METRIC_TIMESTAMP=$(date +%s)
  BACKUP_SIZE=$(stat --printf='%s' "$ARCHIVE_FILE" 2>/dev/null || stat -f '%z' "$ARCHIVE_FILE" 2>/dev/null || echo 0)
  INSTANCE="${INSTANCE_LABEL:-${DOMAIN:-unknown}}"
  curl -sf -X POST "${BUNKER_OPS_REMOTE_WRITE_URL}" \
    --data-binary "cm_backup_last_success_timestamp{instance=\"${INSTANCE}\"} ${METRIC_TIMESTAMP}
cm_backup_size_bytes{instance=\"${INSTANCE}\"} ${BACKUP_SIZE}" \
    && echo "Pushed backup metrics to Bunker Ops." \
    || echo "[WARN] Failed to push backup metrics to Bunker Ops."
  echo ""
fi

echo "=========================================="
echo "  Backup complete!"
echo "  Archive: ${ARCHIVE_FILE}"
echo "=========================================="
