#!/bin/bash
# =============================================================================
# nextcloud备份脚本
# 功能：远程Nextcloud维护模式切换、数据库备份、文件同步及清理
# 版本：1.0.0
# 作者：Shell脚本工程师
# 许可证：MIT License
# 依赖：ssh, rsync, docker (远程主机), mariadb-client (远程主机)
# =============================================================================

set -euo pipefail
IFS=$'\n\t'

# > 全局常量定义
readonly SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_DIR="/root/wdd/backup"
readonly LOCK_FILE="/root/wdd/backup/${SCRIPT_NAME}.lock"

# > 远程主机配置
readonly REMOTE_HOST="s5"
readonly REMOTE_PORT="22333"
readonly REMOTE_USER="root"
readonly REMOTE_NEXTCLOUD_DIR="/data/nextcloud"
readonly REMOTE_DB_CONTAINER="nextcloud-db"
readonly REMOTE_WEB_CONTAINER="nextcloud_web"

# > 数据库配置
readonly DB_NAME="nextcloud"
readonly DB_USER="nextcloud"
readonly DB_PASSWORD="boge14@Level5"

# > 本地配置
readonly LOCAL_BACKUP_DIR="/data/s5_146-56-159-175/nextcloud"

# > 日志配置
readonly LOG_DIR="${SCRIPT_DIR}/logs"
readonly LOG_FILE="${LOG_DIR}/nextcloud_backup_$(date +%Y%m%d).log"

# > 颜色输出定义
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly NC='\033[0m'

# =============================================================================
# 日志函数集
# =============================================================================

###
# 初始化日志系统
# @require 无
# @return 0 成功 | >0 失败
###
init_log_system() {
  mkdir -p "${LOG_DIR}" || return 1
  touch "${LOG_FILE}" || return 1
  return 0
}

###
# 记录日志消息
# @param level string 日志级别（DEBUG/INFO/WARN/ERROR）
# @param message string 日志消息
# @require LOG_FILE
# @return 0 成功
###
log_message() {
  local level="$1"
  local message="$2"
  local timestamp
  timestamp=$(date '+%Y-%m-%d %H:%M:%S')

  case "${level}" in
  "DEBUG") echo -e "${BLUE}[DEBUG]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
  "INFO") echo -e "${GREEN}[INFO]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
  "WARN") echo -e "${YELLOW}[WARN]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" >&2 ;;
  "ERROR") echo -e "${RED}[ERROR]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" >&2 ;;
  *) echo "${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
  esac
  return 0
}

# =============================================================================
# 工具函数集
# =============================================================================

###
# 检查命令是否存在
# @param command_name string 命令名称
# @require 无
# @return 0 存在 | 1 不存在
###
check_command() {
  local command_name="$1"
  if ! command -v "${command_name}" >/dev/null 2>&1; then
    log_message "ERROR" "命令不存在: ${command_name}"
    return 1
  fi
  return 0
}

###
# 执行远程SSH命令
# @param command string 要执行的命令
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_USER
# @return 远程命令的退出码
###
execute_remote_command() {
  local command="$1"
  ssh -p "${REMOTE_PORT}" "${REMOTE_USER}@${REMOTE_HOST}" "${command}"
  return $?
}

###
# 创建锁文件防止并发执行
# @require LOCK_FILE
# @return 0 成功获取锁 | 1 锁已存在
###
acquire_lock() {
  if [ -e "${LOCK_FILE}" ]; then
    log_message "ERROR" "备份任务正在运行或异常退出，请检查锁文件: ${LOCK_FILE}"
    return 1
  fi
  echo "$$" > "${LOCK_FILE}"
  trap 'release_lock' EXIT
  return 0
}

###
# 释放锁文件
# @require LOCK_FILE
# @return 0 成功
###
release_lock() {
  [ -e "${LOCK_FILE}" ] && rm -f "${LOCK_FILE}"
  return 0
}

# =============================================================================
# Nextcloud核心备份函数
# =============================================================================

###
# 启用Nextcloud维护模式
# @require execute_remote_command, REMOTE_WEB_CONTAINER
# @return 0 成功 | >0 失败
###
enable_maintenance_mode() {
  log_message "INFO" "启用Nextcloud维护模式..."

  local maintenance_cmd="docker exec -u www-data ${REMOTE_WEB_CONTAINER} php occ maintenance:mode --on"

  if ! execute_remote_command "${maintenance_cmd}"; then
    log_message "ERROR" "启用维护模式失败"
    return 1
  fi

  log_message "INFO" "维护模式已启用"
  return 0
}

###
# 禁用Nextcloud维护模式
# @require execute_remote_command, REMOTE_WEB_CONTAINER
# @return 0 成功 | >0 失败
###
disable_maintenance_mode() {
  log_message "INFO" "禁用Nextcloud维护模式..."

  local maintenance_cmd="docker exec -u www-data  ${REMOTE_WEB_CONTAINER} php occ maintenance:mode --off"

  if ! execute_remote_command "${maintenance_cmd}"; then
    log_message "ERROR" "禁用维护模式失败"
    return 1
  fi

  log_message "INFO" "维护模式已禁用"
  return 0
}

###
# 远程执行MariaDB数据库备份
# @require execute_remote_command, REMOTE_DB_CONTAINER, DB_NAME, DB_USER, DB_PASSWORD, REMOTE_NEXTCLOUD_DIR
# @return 0 成功 | >0 失败
###
backup_database() {
  log_message "INFO" "开始数据库备份..."

  local backup_file="${REMOTE_NEXTCLOUD_DIR}/nextcloud-db_backup_$(date +%Y%m%d-%H%M%S).sql"
  local backup_cmd="docker exec ${REMOTE_DB_CONTAINER} mariadb-dump --single-transaction -h localhost -u ${DB_USER} -p'${DB_PASSWORD}' ${DB_NAME} > ${backup_file}"

  if ! execute_remote_command "${backup_cmd}"; then
    log_message "ERROR" "数据库备份失败"
    return 1
  fi

  # > 验证备份文件是否创建成功
  local verify_cmd="[ -f \"${backup_file}\" ] && echo \"exists\" || echo \"missing\""
  if [ "$(execute_remote_command "${verify_cmd}")" != "exists" ]; then
    log_message "ERROR" "数据库备份文件创建失败"
    return 1
  fi

  log_message "INFO" "数据库备份完成: ${backup_file}"
  return 0
}

###
# 使用rsync同步Nextcloud文件到本地
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_USER, REMOTE_NEXTCLOUD_DIR, LOCAL_BACKUP_DIR
# @return 0 成功 | >0 失败
###
sync_nextcloud_files() {
  log_message "INFO" "开始同步Nextcloud文件到本地..."

  # > 创建本地暂存目录
  mkdir -p "${LOCAL_BACKUP_DIR}" || {
    log_message "ERROR" "创建本地暂存目录失败: ${LOCAL_BACKUP_DIR}"
    return 1
  }

  # > 构建rsync命令
  local rsync_cmd="rsync -avz --progress -e 'ssh -p ${REMOTE_PORT}'"
  rsync_cmd+=" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_NEXTCLOUD_DIR}/"
  rsync_cmd+=" ${LOCAL_BACKUP_DIR}/"

  # > 执行rsync同步
  if ! eval "${rsync_cmd}"; then
    log_message "ERROR" "Nextcloud文件同步失败"
    return 1
  fi

  log_message "INFO" "Nextcloud文件同步完成"
  return 0
}


###
# 远程删除数据库备份文件
# @require execute_remote_command, REMOTE_NEXTCLOUD_DIR
# @return 0 成功 | >0 失败
###
remote_cleanup_backup() {
  log_message "INFO" "清理远程数据库备份文件..."

  local cleanup_cmd="rm -f ${REMOTE_NEXTCLOUD_DIR}/nextcloud-db_backup_*.sql"

  if ! execute_remote_command "${cleanup_cmd}"; then
    log_message "ERROR" "远程清理失败"
    return 1
  fi

  log_message "INFO" "远程清理完成"
  return 0
}

###
# 清理本地暂存目录
# @require LOCAL_BACKUP_DIR
# @return 0 成功
###
local_cleanup() {
  log_message "INFO" "清理本地暂存目录..."
  [ -d "${LOCAL_BACKUP_DIR}" ] && rm -rf "${LOCAL_BACKUP_DIR}"
  return 0
}

# =============================================================================
# 主执行流程
# =============================================================================

###
# 主备份流程
# @require 所有上述函数
# @return 0 成功 | >0 失败
###
main_backup_process() {
  log_message "INFO" "=== 开始Nextcloud备份任务 ==="

  # > 检查依赖命令
  local required_commands=("ssh" "rsync")
  for cmd in "${required_commands[@]}"; do
    if ! check_command "${cmd}"; then
      return 1
    fi
  done

  # > 执行备份流程
  local steps=(
    enable_maintenance_mode
    backup_database
    sync_nextcloud_files
    remote_cleanup_backup
    disable_maintenance_mode
#    local_cleanup
  )

  for step in "${steps[@]}"; do
    if ! "${step}"; then
      log_message "ERROR" "备份任务失败，正在尝试恢复..."
      # > 尝试禁用维护模式
      disable_maintenance_mode || true
      return 1
    fi
  done

  log_message "INFO" "=== Nextcloud备份任务完成 ==="
  return 0
}

# =============================================================================
# 脚本入口点
# =============================================================================

# > 设置错误处理
trap 'log_message "ERROR" "脚本异常退出"; disable_maintenance_mode || true; release_lock; exit 1' ERR

# > 主执行块
main() {
  if ! acquire_lock; then
    exit 1
  fi

  if ! init_log_system; then
    log_message "ERROR" "日志系统初始化失败"
    exit 1
  fi

  if ! main_backup_process; then
    log_message "ERROR" "备份任务执行失败"
    exit 1
  fi

  release_lock
  exit 0
}

# > 脚本执行入口
main "$@"

# =============================================================================
# 函数调用关系图
# =============================================================================
# main
# ├── acquire_lock
# ├── init_log_system
# └── main_backup_process
#     ├── check_command (多次调用)
#     ├── enable_maintenance_mode
#     │   └── execute_remote_command
#     ├── backup_database
#     │   └── execute_remote_command
#     ├── sync_nextcloud_files
#     ├── move_to_backup_dir
#     ├── remote_cleanup_backup
#     │   └── execute_remote_command
#     ├── disable_maintenance_mode
#     │   └── execute_remote_command
#     └── local_cleanup

