#!/bin/bash
# =====================================================================
#  AFMAX CDN 全系统跨版本升级脚本（终极版）
#  适配：Ubuntu 22→24/CentOS7→9/Debian11→12/Alpine3.19→3.20（禁用外网VPS）
#  特性：跨版本+强制AFMAX国内源+IPv4+自动备份+分级升级
# =====================================================================
# 设置在任何命令失败时立即退出，并捕获未设置的变量和管道中的失败
set -euo pipefail

# 基础配置
RED='\033[31m'; GREEN='\033[32m'; YELLOW='\033[33m'; NC='\033[0m'
BACKUP_SUFFIX=$(date +%Y%m%d_%H%M%S)
AFMAX_APT="https://apt-mirror.afmax.cn"
AFMAX_YUM="https://yum-mirror.afmax.cn" # 这个YUM变量也用于Alpine的APK源，可以接受
LOG_FILE="/var/log/afmax-cross-upgrade-$BACKUP_SUFFIX.log"
SUPPORTED_CROSS=("ubuntu:22.04→24.04" "debian:11→12" "centos:7→9" "alpine:3.19→3.20")

# 全局日志函数，将输出同时打印到控制台和日志文件
# usage: log_run <command> [args...]
log_run() {
    echo -e "${GREEN}Executing: $*${NC}" | tee -a "$LOG_FILE"
    # 执行命令，将其标准输出和标准错误同时重定向到控制台和日志文件
    if ! "$@" 2>&1 | tee -a "$LOG_FILE"; then
        local status=${PIPESTATUS[0]} # 获取前一个命令的退出状态
        echo -e "${RED}❌ 命令执行失败: '$*' (退出码: $status)${NC}" | tee -a "$LOG_FILE"
        exit "$status" # 如果命令失败，则脚本退出
    fi
}

# 错误捕获，在脚本中断时提供更详细的日志信息
trap 'echo -e "\033[31m❌ 跨版本升级中断！请检查日志文件: $LOG_FILE 查看详细信息。\033[0m" | tee -a "$LOG_FILE"' ERR

# 1. 跨版本警告（禁用外网专属）
# 此函数只输出通用警告，不依赖 OS 或 VER 变量
warning_cross(){
    echo -e "${YELLOW}========== 全系统跨版本升级警告（无境外流量）==========${NC}" | tee -a "$LOG_FILE"
    echo -e "${RED}中文：${NC}" | tee -a "$LOG_FILE"
    echo -e "  1. 全程使用AFMAX国内源，无境外流量，适配禁用外网的VPS。" | tee -a "$LOG_FILE"
    echo -e "  2. 跨版本升级风险极高，请务必在操作前备份所有业务数据（数据库/配置/快照）。" | tee -a "$LOG_FILE"
    echo -e "  3. 支持升级路径：${SUPPORTED_CROSS[*]}。" | tee -a "$LOG_FILE"
    echo -e "  4. 升级后需重启系统，部分第三方服务需重建（如Nginx/PHP）。" | tee -a "$LOG_FILE"
    echo -e "${RED}EN：${NC}" | tee -a "$LOG_FILE"
    echo -e "  1. Use AFMAX China CDN only, no overseas traffic for blocked VPS." | tee -a "$LOG_FILE"
    echo -e "  2. High risk, backup all business data (DB/config/snapshot) first." | tee -a "$LOG_FILE"
    echo -e "  3. Supported paths: ${SUPPORTED_CROSS[*]}." | tee -a "$LOG_FILE"
    echo -e "  4. Reboot after upgrade, rebuild 3rd-party services if needed." | tee -a "$LOG_FILE"
    echo -e "${YELLOW}======================================================${NC}" | tee -a "$LOG_FILE"
}

# 2. 前置检查（root + 系统版本 + AFMAX源）
pre_check(){
    echo -e "${GREEN}🔍 执行前置检查...${NC}" | tee -a "$LOG_FILE"
    # 检查root
    if [ "$(id -u)" -ne 0 ]; then
        echo -e "${RED}❌ 请以root权限执行${NC}" | tee -a "$LOG_FILE"; exit 1
    fi
    echo -e "${GREEN}✅ Root权限检查通过。${NC}" | tee -a "$LOG_FILE"

    # 检测系统
    if [ -f /etc/os-release ]; then
        . /etc/os-release
        OS="$ID"
        VER="$VERSION_ID"
        OS_PRETTY="$PRETTY_NAME"
    else
        echo -e "${RED}❌ 无法检测系统类型${NC}" | tee -a "$LOG_FILE"; exit 1
    fi
    echo -e "${GREEN}✅ 检测到当前系统：$OS_PRETTY (ID: $OS, Version: $VER)${NC}" | tee -a "$LOG_FILE"

    # 检查升级路径兼容性
    local CROSS_VALID="no"
    case "$OS" in
        ubuntu)
            [ "$VER" = "22.04" ] && CROSS_VALID="yes" && TARGET_VER="24.04" && TARGET_CODE="noble"
            ;;
        debian)
            [ "$VER" = "11" ] && CROSS_VALID="yes" && TARGET_VER="12" && TARGET_CODE="bookworm"
            ;;
        centos)
            # 使用更精确的方式检查 CentOS 7
            if [ -f /etc/redhat-release ] && grep -q "CentOS Linux release 7" /etc/redhat-release; then
                CROSS_VALID="yes" && TARGET_VER="9"
            fi
            ;;
        alpine)
            [ "$VER" = "3.19" ] && CROSS_VALID="yes" && TARGET_VER="3.20"
            ;;
        *) # 默认处理未知OS
            echo -e "${RED}❌ 不支持的系统：$OS_PRETTY${NC}" | tee -a "$LOG_FILE"; exit 1
            ;;
    esac
    if [ "$CROSS_VALID" = "no" ]; then
        echo -e "${RED}❌ 不支持的跨版本路径：$OS $VER，仅支持${SUPPORTED_CROSS[*]}${NC}" | tee -a "$LOG_FILE"; exit 1
    fi
    echo -e "${GREEN}✅ 检测到兼容升级路径：$OS $VER→$TARGET_VER${NC}" | tee -a "$LOG_FILE"

    # 根据系统类型检查对应的AFMAX源连通性
    echo -e "${GREEN}🔍 检测AFMAX国内源连通性...${NC}" | tee -a "$LOG_FILE"
    local AFMAX_CHECK_URL=""
    case "$OS" in
        ubuntu|debian) AFMAX_CHECK_URL="$AFMAX_APT" ;;
        centos|rocky|alma|alpine) AFMAX_CHECK_URL="$AFMAX_YUM" ;;
        *) echo -e "${RED}❌ 无法确定要检测的AFMAX源URL${NC}" | tee -a "$LOG_FILE"; exit 1 ;;
    esac

    if ! curl -s --connect-timeout 8 --ipv4 "$AFMAX_CHECK_URL" >/dev/null; then
        echo -e "${RED}❌ AFMAX源（$AFMAX_CHECK_URL）不通，请检查网络/IPv4配置${NC}" | tee -a "$LOG_FILE"; exit 1
    fi
    echo -e "${GREEN}✅ AFMAX源连通性正常：$AFMAX_CHECK_URL${NC}" | tee -a "$LOG_FILE"
}

# 3. 全量备份（源+关键配置）
full_backup(){
    BACKUP_DIR="/root/afmax-cross-upgrade-bak-$BACKUP_SUFFIX"
    log_run mkdir -p "$BACKUP_DIR"

    echo -e "${GREEN}🔍 正在备份系统配置...${NC}" | tee -a "$LOG_FILE"
    case "$OS" in
        ubuntu|debian)
            log_run cp -a /etc/apt/sources.list "$BACKUP_DIR/"
            if [ -d /etc/apt/sources.list.d ]; then
                log_run cp -a /etc/apt/sources.list.d "$BACKUP_DIR/"
            fi
            if [ -d /etc/default ]; then # Ubuntu/Debian 特有配置
                log_run cp -a /etc/default "$BACKUP_DIR/"
            fi
            ;;
        centos)
            if [ -d /etc/yum.repos.d ]; then
                log_run cp -a /etc/yum.repos.d "$BACKUP_DIR/"
            fi
            if [ -d /etc/sysconfig ]; then # CentOS 特有配置
                log_run cp -a /etc/sysconfig "$BACKUP_DIR/"
            fi
            ;;
        alpine)
            log_run cp -a /etc/apk/repositories "$BACKUP_DIR/"
            if [ -d /etc/conf.d ]; then # Alpine 特有配置
                log_run cp -a /etc/conf.d "$BACKUP_DIR/"
            fi
            ;;
    esac
    # 通用配置备份（在复制前检查是否存在）
    if [ -d /etc/systemd ]; then
        log_run cp -a /etc/systemd "$BACKUP_DIR/"
    fi
    if [ -f /etc/fstab ]; then
        log_run cp -a /etc/fstab "$BACKUP_DIR/"
    fi
    if [ -d /etc/sudoers.d ]; then
        log_run cp -a /etc/sudoers.d "$BACKUP_DIR/"
    fi
    if [ -d /etc/ssh ]; then
        log_run cp -a /etc/ssh "$BACKUP_DIR/"
    fi

    echo -e "${YELLOW}⚠️ 关键系统配置已备份至：$BACKUP_DIR${NC}" | tee -a "$LOG_FILE"
    
    echo -e "\n${YELLOW}🚨 重要提示：您即将进行高风险的跨版本系统升级。${NC}" | tee -a "$LOG_FILE"
    read -rp "$(echo -e "${YELLOW}请再次确认您已完整备份所有业务数据（数据库/文件/快照等）？(Y/N): ${NC}")" ans
    if [[ "$ans" != [yY] ]]; then
        echo -e "${RED}❌ 用户取消，业务数据备份未确认，脚本已退出。${NC}" | tee -a "$LOG_FILE"
        exit 1
    fi
    echo -e "${GREEN}✅ 业务数据备份已确认。${NC}" | tee -a "$LOG_FILE"
}

# 4. 系统专属跨版本升级逻辑（无境外流量）
# 4.1 Ubuntu 22.04→24.04
cross_ubuntu(){
    local CURRENT_CODE="jammy"
    # 步骤1：升级22.04到最新补丁（AFMAX源）
    echo -e "${GREEN}🔍 第一步：升级Ubuntu 22.04至最新补丁${NC}" | tee -a "$LOG_FILE"
    log_run sed -i '/^deb/s/^/#/' /etc/apt/sources.list || true # 注释所有主sources.list条目
    log_run rm -f /etc/apt/sources.list.d/*.list 2>/dev/null || true # 删除额外的源文件
    log_run tee /etc/apt/sources.list.d/afmax-jammy.list >/dev/null <<EOF
deb [arch=amd64] $AFMAX_APT/ubuntu $CURRENT_CODE main restricted universe multiverse
deb [arch=amd64] $AFMAX_APT/ubuntu $CURRENT_CODE-updates main restricted universe multiverse
deb [arch=amd64] $AFMAX_APT/ubuntu $CURRENT_CODE-security main restricted universe multiverse
EOF
    log_run apt clean
    log_run apt -o Acquire::ForceIPv4=true update -y --allow-releaseinfo-change
    log_run apt -o Acquire::ForceIPv4=true full-upgrade -y

    # 步骤2：切换到24.04 AFMAX源
    echo -e "${GREEN}🔍 第二步：切换到Ubuntu 24.04 AFMAX源并升级${NC}" | tee -a "$LOG_FILE"
    log_run rm -f /etc/apt/sources.list.d/afmax-jammy.list
    log_run tee /etc/apt/sources.list.d/afmax-noble.list >/dev/null <<EOF
deb [arch=amd64] $AFMAX_APT/ubuntu $TARGET_CODE main restricted universe multiverse
deb [arch=amd64] $AFMAX_APT/ubuntu $TARGET_CODE-updates main restricted universe multiverse
deb [arch=amd64] $AFMAX_APT/ubuntu $TARGET_CODE-security main restricted universe multiverse
EOF
    log_run apt -o Acquire::ForceIPv4=true update -y --allow-releaseinfo-change
    log_run apt -o Acquire::ForceIPv4=true full-upgrade -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold"
    log_run apt autoremove -y
}

# 4.2 Debian 11→12
cross_debian(){
    local CURRENT_CODE="bullseye"
    # 步骤1：升级11到最新补丁
    echo -e "${GREEN}🔍 第一步：升级Debian 11至最新补丁${NC}" | tee -a "$LOG_FILE"
    log_run sed -i '/^deb/s/^/#/' /etc/apt/sources.list || true
    log_run rm -f /etc/apt/sources.list.d/*.list 2>/dev/null || true
    log_run tee /etc/apt/sources.list.d/afmax-bullseye.list >/dev/null <<EOF
deb [arch=amd64] $AFMAX_APT/debian $CURRENT_CODE main contrib non-free
deb [arch=amd64] $AFMAX_APT/debian $CURRENT_CODE-updates main contrib non-free
deb [arch=amd64] $AFMAX_APT/debian $CURRENT_CODE-security main contrib non-free
EOF
    log_run apt clean
    log_run apt -o Acquire::ForceIPv4=true update -y --allow-releaseinfo-change
    log_run apt -o Acquire::ForceIPv4=true full-upgrade -y

    # 步骤2：切换到12 AFMAX源
    echo -e "${GREEN}🔍 第二步：切换到Debian 12 AFMAX源并升级${NC}" | tee -a "$LOG_FILE"
    log_run rm -f /etc/apt/sources.list.d/afmax-bullseye.list
    log_run tee /etc/apt/sources.list.d/afmax-bookworm.list >/dev/null <<EOF
deb [arch=amd64] $AFMAX_APT/debian $TARGET_CODE main contrib non-free non-free-firmware
deb [arch=amd64] $AFMAX_APT/debian $TARGET_CODE-updates main contrib non-free non-free-firmware
deb [arch=amd64] $AFMAX_APT/debian $TARGET_CODE-security main contrib non-free non-free-firmware
EOF
    log_run apt -o Acquire::ForceIPv4=true update -y --allow-releaseinfo-change
    log_run apt -o Acquire::ForceIPv4=true full-upgrade -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold"
    log_run apt autoremove -y
}

# 4.3 CentOS 7→9
cross_centos(){
    echo -e "${YELLOW}⚠️ 警告：CentOS 7→9 是一个极其复杂的跨版本升级，请务必做好数据备份和风险评估。${NC}" | tee -a "$LOG_FILE"
    echo -e "${YELLOW}此过程可能耗时较长，且存在高风险，请勿中断！${NC}" | tee -a "$LOG_FILE"
    
    # 步骤1：升级7到最新补丁
    echo -e "${GREEN}🔍 第一步：升级CentOS 7至最新补丁${NC}" | tee -a "$LOG_FILE"
    log_run rm -f /etc/yum.repos.d/*.repo 2>/dev/null || true
    log_run tee /etc/yum.repos.d/afmax-centos7.repo >/dev/null <<EOF
[afmax-centos7-base]
name=AFMAX CentOS 7 Base
baseurl=$AFMAX_YUM/7/os/\$basearch/
gpgcheck=0
enabled=1
[afmax-centos7-updates]
name=AFMAX CentOS 7 Updates
baseurl=$AFMAX_YUM/7/updates/\$basearch/
gpgcheck=0
enabled=1
EOF
    log_run yum clean all
    log_run yum makecache fast
    log_run yum update -y --skip-broken

    # 步骤2：安装DNF (如果未安装)
    echo -e "${GREEN}🔍 第二步：安装DNF包管理器${NC}" | tee -a "$LOG_FILE"
    if ! command -v dnf &> /dev/null; then
        log_run yum install -y dnf --skip-broken
    else
        echo -e "${GREEN}✅ DNF已安装。${NC}" | tee -a "$LOG_FILE"
    fi

    # 步骤3：切换到9 AFMAX源并进行升级
    echo -e "${GREEN}🔍 第三步：切换到CentOS 9 AFMAX源并执行跨版本升级${NC}" | tee -a "$LOG_FILE"
    log_run rm -f /etc/yum.repos.d/afmax-centos7.repo
    log_run tee /etc/yum.repos.d/afmax-centos9.repo >/dev/null <<EOF
[afmax-centos9-baseos]
name=AFMAX CentOS 9 Stream BaseOS
baseurl=$AFMAX_YUM/9-stream/BaseOS/\$basearch/os/
gpgcheck=0
enabled=1
[afmax-centos9-appstream]
name=AFMAX CentOS 9 Stream AppStream
baseurl=$AFMAX_YUM/9-stream/AppStream/\$basearch/os/
gpgcheck=0
enabled=1
[afmax-centos9-extras]
name=AFMAX CentOS 9 Stream Extras
baseurl=$AFMAX_YUM/9-stream/Extras/\$basearch/os/
gpgcheck=0
enabled=1
EOF
    log_run dnf clean all
    log_run dnf makecache
    # 注意：直接从 7 到 9 的 DNF 升级非常规，存在高风险。
    # `--releasever` 配合 `system-upgrade` 效果更佳，但 `system-upgrade` 通常是逐版本升级。
    # 这里我们按照原意执行一个激进的升级尝试。
    log_run dnf upgrade -y --releasever=9 --skip-broken
    echo -e "${YELLOW}⚠️ CentOS 7→9 升级完成，请务必手动验证系统状态和关键服务。${NC}" | tee -a "$LOG_FILE"
}

# 4.4 Alpine 3.19→3.20
cross_alpine(){
    echo -e "${GREEN}🔍 切换到Alpine $TARGET_VER AFMAX源并升级${NC}" | tee -a "$LOG_FILE"
    log_run tee /etc/apk/repositories >/dev/null <<EOF
$AFMAX_YUM/alpine/v$TARGET_VER/main
$AFMAX_YUM/alpine/v$TARGET_VER/community
EOF
    log_run apk update
    log_run apk upgrade -U
}

# 5. 主流程
main(){
    # 在日志文件创建前，先在控制台输出提示
    echo -e "${YELLOW}🚀 正在启动 AFMAX CDN 全系统跨版本升级脚本...${NC}"

    # 确保日志文件可以被创建 (移动到这里，以确保 LOG_FILE 在 log_run 第一次调用时已就绪)
    touch "$LOG_FILE" || { echo -e "${RED}❌ 无法创建日志文件: $LOG_FILE. 请检查权限。${NC}"; exit 1; }
    echo -e "${GREEN}✅ 升级日志文件：$LOG_FILE${NC}" | tee -a "$LOG_FILE"

    warning_cross # 调用通用警告
    pre_check     # 在此函数中，OS, VER, TARGET_VER, TARGET_CODE 被正确设置

    # 在 pre_check 之后，根据实际检测到的 OS 和 VER 显示特定警告
    if [ "$OS" = "centos" ] && [ "$VER" = "7" ]; then 
        echo -e "     ${RED}特别警告：CentOS 7→9 为重大版本跳跃，极易出现问题，建议重新安装或分步升级。此路径请慎重考虑！${NC}" | tee -a "$LOG_FILE"
    fi

    echo -e "\n${RED}!!! 最终确认 !!!${NC}" | tee -a "$LOG_FILE"
    echo -e "${YELLOW}您已确认了解跨版本升级的全部风险，且已完成所有业务数据备份。${NC}" | tee -a "$LOG_FILE"
    read -rp "$(echo -e "${YELLOW}输入 'Y' 确认开始此高风险的系统跨版本升级操作 (输入其他键取消): ${NC}")" final_confirm
    if [[ "$final_confirm" != [yY] ]]; then
        echo -e "${RED}❌ 用户取消，脚本已退出。${NC}" | tee -a "$LOG_FILE"
        exit 0
    fi
    echo -e "${GREEN}✅ 最终确认通过，正在开始系统升级流程...${NC}" | tee -a "$LOG_FILE"

    full_backup # 这个函数里有业务数据备份的确认
    
    # 执行对应系统跨版本升级
    case "$OS" in
        ubuntu) log_run cross_ubuntu ;;
        debian) log_run cross_debian ;;
        centos) log_run cross_centos ;;
        alpine) log_run cross_alpine ;;
        *) echo -e "${RED}❌ 未知或不支持的操作系统 ($OS)，无法执行升级。${NC}" | tee -a "$LOG_FILE"; exit 1 ;; # 增加默认处理
    esac
    echo -e "${GREEN}🎉 跨版本升级完成！全程无境外流量${NC}" | tee -a "$LOG_FILE"
    echo -e "${YELLOW}⚠️ 关键操作：${NC}" | tee -a "$LOG_FILE"
    echo -e "  1. 升级日志：$LOG_FILE" | tee -a "$LOG_FILE"
    echo -e "  2. 执行 reboot 重启系统生效" | tee -a "$LOG_FILE"
    echo -e "  3. 验证版本：cat /etc/os-release" | tee -a "$LOG_FILE"
    echo -e "  4. 配置备份目录：$BACKUP_DIR（异常时可恢复）" | tee -a "$LOG_FILE"
    if [ "$OS" = "centos" ]; then
        echo -e "  5. CentOS 7→9 为重大版本跳跃，需额外重建或重新配置第三方服务（如Nginx/PHP/MySQL）并手动验证系统稳定性和功能。强烈建议重启后进行全面检查。" | tee -a "$LOG_FILE"
    fi
}

# 启动脚本
main