#!/usr/bin/env bash
set -Eeuo pipefail

BACKUP_ROOT=/home/admin/backups/sub2api
LOG_FILE="$BACKUP_ROOT/backup.log"
TRASH_DIR=/home/admin/.trash
STAMP_DIR="$BACKUP_ROOT/meta"
STAMP_FILE="$STAMP_DIR/redis-verify-last-date.txt"
REDIS_VERIFY_CONTAINER=""
REDIS_VERIFY_DIR=""
FAILED_LINE="?"

log() {
  printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" | tee -a "$LOG_FILE"
}

move_to_trash() {
  local src="$1"
  local base
  local dest
  base=$(basename "$src")
  dest="$TRASH_DIR/${base}_$(date +%Y%m%d_%H%M%S)"
  mkdir -p "$TRASH_DIR" 2>/dev/null || true
  mv "$src" "$dest" 2>/dev/null || true
}

archive_dir_if_exists() {
  local src="$1"
  [ -d "$src" ] || return 0
  move_to_trash "$src"
}

find_latest_rdb() {
  find "$BACKUP_ROOT" \
    -maxdepth 3 \
    -type f \
    -path "$BACKUP_ROOT/backup-date-*/redis/dump_*.rdb" \
    2>/dev/null \
    | sort \
    | tail -n 1
}

log_verify_container_state() {
  local container="$1"
  local status=""
  status=$(docker ps -a --filter "name=^${container}$" --format '{{.Names}}|{{.Status}}' | head -n 1 || true)
  if [ -n "$status" ]; then
    log "Redis 恢复校验容器状态: $status"
  else
    log "Redis 恢复校验容器状态: missing"
  fi

  local container_logs=""
  container_logs=$(docker logs "$container" 2>&1 | tail -n 80 || true)
  if [ -n "$container_logs" ]; then
    while IFS= read -r line; do
      log "redis-verify-log: $line"
    done <<< "$container_logs"
  fi
}

wait_for_redis_dbsize() {
  local container="$1"
  local value=""
  for i in $(seq 1 180); do
    value=$(docker exec "$container" redis-cli --raw DBSIZE 2>/dev/null | tr -d '\r' || true)
    if printf '%s' "$value" | grep -Eq '^[0-9]+$'; then
      printf '%s\n' "$value"
      return 0
    fi

    if ! docker ps --filter "name=^${container}$" --format '{{.Names}}' | grep -qx "$container"; then
      log "Redis 恢复校验容器在第 ${i} 秒前已退出"
      return 1
    fi

    sleep 1
  done

  log 'Redis 恢复校验等待超时：180 秒内未拿到 DBSIZE'
  return 1
}

cleanup() {
  local rc=$?
  if [ -n "$REDIS_VERIFY_CONTAINER" ]; then
    docker rm -f "$REDIS_VERIFY_CONTAINER" >/dev/null 2>&1 || true
    REDIS_VERIFY_CONTAINER=""
  fi
  if [ -n "$REDIS_VERIFY_DIR" ]; then
    archive_dir_if_exists "$REDIS_VERIFY_DIR"
    REDIS_VERIFY_DIR=""
  fi
  if [ "$rc" -ne 0 ]; then
    log "redis verify script aborted rc=$rc line=$FAILED_LINE"
  fi
  exit "$rc"
}

trap 'FAILED_LINE=$LINENO' ERR
trap cleanup EXIT

mkdir -p "$TRASH_DIR" "$STAMP_DIR"
touch "$LOG_FILE"

TODAY=$(date +%F)
if [ -f "$STAMP_FILE" ] && [ "$(cat "$STAMP_FILE" 2>/dev/null || true)" = "$TODAY" ]; then
  log 'Redis 恢复校验今日已执行，跳过'
  exit 0
fi

LATEST_RDB=$(find_latest_rdb)
[ -n "$LATEST_RDB" ] || { log '未找到可用于恢复校验的 Redis RDB，跳过'; exit 0; }

REDIS_CONTAINER=redis-base
REDIS_IMAGE=$(docker inspect "$REDIS_CONTAINER" --format '{{.Config.Image}}')
[ -n "$REDIS_IMAGE" ] || { log '未获取到 Redis image，跳过'; exit 0; }

log "开始 Redis 每日恢复校验: file=$LATEST_RDB image=$REDIS_IMAGE"
REDIS_VERIFY_DIR=$(mktemp -d "$BACKUP_ROOT/sub2api-redis-verify.XXXXXX")
cp "$LATEST_RDB" "$REDIS_VERIFY_DIR/dump.rdb"
REDIS_VERIFY_CONTAINER="redis-backup-verify-daily-$(date +%Y%m%d_%H%M%S)"
docker rm -f "$REDIS_VERIFY_CONTAINER" >/dev/null 2>&1 || true
docker run -d --name "$REDIS_VERIFY_CONTAINER" -v "$REDIS_VERIFY_DIR:/data" "$REDIS_IMAGE" redis-server --dir /data --dbfilename dump.rdb --save '' --appendonly no >/dev/null

if ! REDIS_BACKUP_DBSIZE=$(wait_for_redis_dbsize "$REDIS_VERIFY_CONTAINER"); then
  log_verify_container_state "$REDIS_VERIFY_CONTAINER"
  exit 1
fi

log "Redis 每日恢复校验成功: dbsize=$REDIS_BACKUP_DBSIZE"
printf '%s\n' "$TODAY" > "$STAMP_FILE"
