#!/usr/bin/env bash
# backup-full.sh —— 每日全量备份编排脚本（02:00 运行）
# 内容：MySQL xtrabackup 全量 + PostgreSQL pg_dump + Marzban SQLite
# 备份 → age 加密 → 上传 S3
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "${SCRIPT_DIR}/lib.sh"

TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
START="$(timer_start)"

log_info "========== 全量备份开始 ${TIMESTAMP} =========="

ERRORS=0

# ──────────────────────────────────────────────────────
# 1. MySQL 全量备份（xtrabackup）
# ──────────────────────────────────────────────────────
mysql_full_backup() {
    local target="${BACKUP_DIR}/mysql/full/${TIMESTAMP}"
    local archive="${BACKUP_DIR}/mysql/full/${TIMESTAMP}.tar.gz"
    local s3_key="mysql/full/${TIMESTAMP}.tar.gz"

    log_info "[MySQL] 开始 xtrabackup 全量备份"
    mkdir -p "${target}"

    if ! mysql_ping; then
        log_warn "[MySQL] 无法连接 MySQL，跳过 MySQL 备份"
        return 1
    fi

    # xtrabackup --backup：连接 MySQL 并备份 InnoDB 数据文件
    xtrabackup \
        --backup \
        --host="${MYSQL_HOST}" \
        --port="${MYSQL_PORT}" \
        --user="${MYSQL_USER}" \
        --password="${MYSQL_PASSWORD}" \
        --target-dir="${target}" \
        --compress \
        --compress-threads=2 \
        ${MYSQL_DATADIR:+--datadir="${MYSQL_DATADIR}"} \
        2>&1 | tee "${target}/xtrabackup-backup.log"

    # xtrabackup --prepare：回放 redo log，使备份一致（无需 MySQL 服务）
    xtrabackup \
        --prepare \
        --target-dir="${target}" \
        2>&1 | tee "${target}/xtrabackup-prepare.log"

    # 打包（xtrabackup --compress 已压缩，这里仅归档）
    log_info "[MySQL] 打包备份目录"
    tar -czf "${archive}" -C "$(dirname "${target}")" "$(basename "${target}")"

    # 更新 latest-full 引用（供增量备份使用）
    echo "${target}" > "${BACKUP_DIR}/mysql/latest-full.txt"
    # 清除上一次增量引用
    rm -f "${BACKUP_DIR}/mysql/latest-inc.txt"

    # 加密 + 上传
    encrypt_and_upload "${archive}" "${s3_key}"

    # 清理本地中间文件（保留原始目录供后续增量）
    rm -f "${archive}"

    # 清理 7 天前的全量备份目录
    find "${BACKUP_DIR}/mysql/full" -maxdepth 1 -type d -mtime +7 \
        -not -path "${BACKUP_DIR}/mysql/full" \
        -exec rm -rf {} + 2>/dev/null || true

    log_ok "[MySQL] 全量备份完成: ${target}"
}

# ──────────────────────────────────────────────────────
# 2. PostgreSQL 全量备份（pg_dump）
# ──────────────────────────────────────────────────────
postgres_full_backup() {
    log_info "[PostgreSQL] 开始 pg_dump 全量备份"

    if ! pg_ping; then
        log_warn "[PostgreSQL] 无法连接 PostgreSQL，跳过 PG 备份"
        return 1
    fi

    # 支持多数据库（逗号分隔）
    IFS=',' read -ra DBS <<< "${PG_DATABASES:-postgres}"
    for DB in "${DBS[@]}"; do
        DB="$(echo "${DB}" | tr -d ' ')"
        local archive="${BACKUP_DIR}/postgres/full_${DB}_${TIMESTAMP}.pgdump"
        local s3_key="postgres/full_${DB}_${TIMESTAMP}.pgdump"

        log_info "[PostgreSQL] 备份数据库: ${DB}"
        PGPASSWORD="${PG_PASSWORD:-}" pg_dump \
            --host="${PG_HOST}" \
            --port="${PG_PORT}" \
            --username="${PG_USER:-postgres}" \
            --format=custom \
            --compress=6 \
            --no-password \
            "${DB}" > "${archive}"

        encrypt_and_upload "${archive}" "${s3_key}"
        rm -f "${archive}"
        log_ok "[PostgreSQL] ${DB} 备份完成"
    done
}

# ──────────────────────────────────────────────────────
# 3. Marzban SQLite 备份
# ──────────────────────────────────────────────────────
marzban_backup() {
    local marzban_db="${MARZBAN_DB_PATH:-/var/lib/marzban/db.sqlite3}"
    local archive="${BACKUP_DIR}/marzban/marzban_${TIMESTAMP}.sqlite3.gz"
    local s3_key="marzban/marzban_${TIMESTAMP}.sqlite3.gz"

    if [ ! -f "${marzban_db}" ]; then
        log_warn "[Marzban] SQLite 文件不存在: ${marzban_db}，跳过"
        return 0
    fi

    log_info "[Marzban] 备份 SQLite: ${marzban_db}"
    # 使用 sqlite3 online backup，避免损坏 WAL
    sqlite3 "${marzban_db}" ".backup '${BACKUP_DIR}/marzban/marzban_${TIMESTAMP}.sqlite3'"
    gzip -9 "${BACKUP_DIR}/marzban/marzban_${TIMESTAMP}.sqlite3"

    encrypt_and_upload "${archive}" "${s3_key}"
    rm -f "${archive}"

    # 清理 30 天前的 SQLite 备份
    find "${BACKUP_DIR}/marzban" -name "*.gz" -mtime +30 -delete 2>/dev/null || true
    log_ok "[Marzban] SQLite 备份完成"
}

# ──────────────────────────────────────────────────────
# 执行
# ──────────────────────────────────────────────────────
mysql_full_backup  || { log_error "[MySQL] 全量备份失败";     ERRORS=$(( ERRORS + 1 )); }
postgres_full_backup || { log_error "[PostgreSQL] 全量备份失败"; ERRORS=$(( ERRORS + 1 )); }
marzban_backup       || { log_error "[Marzban] 备份失败";        ERRORS=$(( ERRORS + 1 )); }

ELAPSED=$(timer_elapsed "${START}")
DURATION=$(format_duration "${ELAPSED}")

if [ "${ERRORS}" -eq 0 ]; then
    log_ok "========== 全量备份完成，耗时 ${DURATION} =========="
    notify "INFO" "全量备份成功，耗时 ${DURATION}"
else
    log_error "========== 全量备份完成（${ERRORS} 个失败），耗时 ${DURATION} =========="
    notify "ERROR" "全量备份完成，但有 ${ERRORS} 个失败，请检查日志"
    exit 1
fi
