#!/bin/bash
# R8125 Network Driver Auto-Installer
# Support: CentOS 7.2-8.5, Ubuntu 18.04-24.04, Debian 10-13
# Usage: Set BASE_URL below, then run as root.

set -euo pipefail

# ==================== 用户配置区 ====================
# 文件服务器根地址，必须以 http:// 或 https:// 开头，末尾不要加 /
# 服务器目录结构示例：
#   BASE_URL/centos/r8125-kmod-9.010.01-1.el7_9.elrepo.rpm
#   BASE_URL/centos/r8125-kmod-9.013.02-1.el8_5.elrepo.rpm
#   BASE_URL/debian_ubuntu/realtek-r8125-dkms_9.016.01-1_amd64.deb
#   BASE_URL/offline/ubuntu20.04.tar.gz   (仅在 OFFLINE_MODE=1 时使用)
BASE_URL="http://s.6p7p.com/kk/drivers/r8125"

# CentOS 各子版本对应的 RPM 驱动版本映射
# 根据实际文件命名规则配置，脚本会自动选择

# Debian/Ubuntu 驱动版本号
DEBIAN_DRIVER_VER="9.016.01"

# 离线模式：设为 1 时，脚本会从 BASE_URL/<os><version>.tar.gz 下载完整依赖包
# 例如: BASE_URL/ubuntu20.04.tar.gz
# 留空或 0 时，使用 apt-get 在线安装编译依赖，仅下载驱动 deb
OFFLINE_MODE="1"
# ===================================================

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'

# 日志函数
log_info()  { echo -e "${GREEN}[INFO]${NC}  $*"; }
log_warn()  { echo -e "${YELLOW}[WARN]${NC}  $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
log_step()  { echo -e "${CYAN}[STEP]${NC}  $*"; }

# 检查 root 权限
check_root() {
    if [[ "$(id -u)" -ne 0 ]]; then
        log_error "此脚本需要 root 权限，请使用 root 或 sudo 运行。"
        exit 1
    fi
}

# 检查必要命令
check_commands() {
    if ! command -v curl &>/dev/null && ! command -v wget &>/dev/null; then
        log_error "系统中未找到 curl 或 wget，无法下载文件。"
        exit 1
    fi
}

# 下载文件到指定路径（带进度条）
download_file() {
    local url="$1"
    local output="$2"
    if command -v curl &>/dev/null; then
        curl -fL --progress-bar -o "$output" "$url"
    elif command -v wget &>/dev/null; then
        wget --show-progress -q -O "$output" "$url"
    else
        log_error "系统中未找到 curl 或 wget，无法下载文件。"
        exit 1
    fi
}

# 检测操作系统
detect_os() {
    if [[ ! -f /etc/os-release ]]; then
        log_error "无法读取 /etc/os-release，无法识别操作系统。"
        exit 1
    fi

    # shellcheck source=/dev/null
    . /etc/os-release
    OS_ID="${ID:-unknown}"
    OS_VER_ID="${VERSION_ID:-unknown}"

    case "$OS_ID" in
        centos|rhel|almalinux|rocky)
            OS_FAMILY="centos"
            ;;
        ubuntu)
            OS_FAMILY="ubuntu"
            ;;
        debian)
            OS_FAMILY="debian"
            ;;
        *)
            log_error "不支持的操作系统: $OS_ID"
            exit 1
            ;;
    esac

    log_info "检测到操作系统: ${BOLD}$OS_ID $OS_VER_ID${NC}，内核: ${BOLD}$(uname -r)${NC}"
}

# CentOS 子版本检测（通过内核版本匹配）
get_centos_subver() {
    local kv
    kv=$(uname -r)

    # CentOS 7 内核前缀映射
    case "$kv" in
        3.10.0-327*)
            echo "7_2"; return ;;
        3.10.0-514*)
            echo "7_3"; return ;;
        3.10.0-693*)
            echo "7_4"; return ;;
        3.10.0-862*)
            echo "7_5"; return ;;
        3.10.0-957*)
            echo "7_6"; return ;;
        3.10.0-1062*)
            echo "7_7"; return ;;
        3.10.0-1127*)
            echo "7_8"; return ;;
        3.10.0-1160*)
            echo "7_9"; return ;;
    esac

    # CentOS 8 内核前缀映射
    case "$kv" in
        4.18.0-80*)
            echo "8_0"; return ;;
        4.18.0-147*)
            echo "8_1"; return ;;
        4.18.0-193*)
            echo "8_2"; return ;;
        4.18.0-240*)
            echo "8_3"; return ;;
        4.18.0-305*)
            echo "8_4"; return ;;
        4.18.0-348*)
            echo "8_5"; return ;;
    esac

    log_error "无法识别的 CentOS/RHEL 内核版本: $kv"
    log_error "本脚本支持 CentOS 7.2-7.9 及 CentOS 8.0-8.5"
    exit 1
}

# 安装 CentOS 驱动
install_centos() {
    local subver rpm_ver rpm_name rpm_url tmpdir
    subver=$(get_centos_subver)

    # 根据实际目录中的文件名映射驱动版本
    case "$subver" in
        7_2|7_3|7_4|7_5|7_6|7_7)
            rpm_ver="9.010.01"
            ;;
        7_8|7_9|8_0|8_1|8_2)
            rpm_ver="9.013.02"
            ;;
        8_3|8_4|8_5)
            # 8.3-8.5 的驱动包需要自行准备，默认使用 9.013.02
            rpm_ver="9.013.02"
            ;;
        *)
            log_error "未知的 CentOS 子版本: $subver"
            exit 1
            ;;
    esac

    rpm_name="r8125-kmod-${rpm_ver}-1.el${subver}.elrepo.rpm"
    rpm_url="${BASE_URL}/centos/${rpm_name}"
    tmpdir=$(mktemp -d)

    log_step "开始下载 CentOS 驱动: $rpm_name"
    if ! download_file "$rpm_url" "$tmpdir/$rpm_name"; then
        log_error "下载失败，请检查 BASE_URL 和文件是否存在: $rpm_url"
        rm -rf "$tmpdir"
        exit 1
    fi

    log_step "安装驱动包..."
    rpm -Uvh "$tmpdir/$rpm_name"

    rm -rf "$tmpdir"
    log_info "CentOS 驱动安装完成。"
}

# 安装 Debian/Ubuntu 驱动
install_debian_ubuntu() {
    local deb_name="realtek-r8125-dkms_${DEBIAN_DRIVER_VER}-1_amd64.deb"
    local deb_url="${BASE_URL}/debian_ubuntu/${deb_name}"
    local tmpdir
    tmpdir=$(mktemp -d)

    if [[ "${OFFLINE_MODE}" == "1" ]]; then
        local tar_name="${OS_ID}${OS_VER_ID}.tar.gz"
        local tar_url="${BASE_URL}/offline/${tar_name}"

        log_step "离线模式：下载完整依赖包 $tar_name"
        log_info "文件较大，请耐心等待下载完成..."
        if ! download_file "$tar_url" "$tmpdir/$tar_name"; then
            log_error "下载失败，请检查 BASE_URL 和文件是否存在: $tar_url"
            rm -rf "$tmpdir"
            exit 1
        fi

        log_step "解压并安装依赖（此步骤可能需要几分钟）..."
        tar -xzf "$tmpdir/$tar_name" -C "$tmpdir"
        local deb_count
        deb_count=$(ls "$tmpdir"/*.deb 2>/dev/null | wc -l)
        log_info "共 $deb_count 个安装包，正在安装..."
        dpkg -i "$tmpdir"/*.deb 2>&1 | while read -r line; do
            if [[ "$line" =~ ^Setting\ up\ (.*)\ \.\.\.$ ]]; then
                echo -e "  ${GREEN}✓${NC} 已安装: $line"
            fi
        done || true
        apt-get install -f -y -qq || true
    else
        log_step "更新软件源并安装编译依赖..."
        apt-get update -qq
        apt-get install -y -qq build-essential dkms

        log_step "开始下载 R8125 DKMS 驱动: $deb_name"
        if ! download_file "$deb_url" "$tmpdir/$deb_name"; then
            log_error "下载失败，请检查 BASE_URL 和文件是否存在: $deb_url"
            rm -rf "$tmpdir"
            exit 1
        fi

        log_step "安装驱动包..."
        if ! dpkg -i "$tmpdir/$deb_name"; then
            log_warn "dpkg 安装返回错误，尝试自动修复依赖..."
        fi
        apt-get install -f -y -qq || log_warn "apt-get 修复依赖时出现问题，可能需要手动处理。"
    fi

    rm -rf "$tmpdir"
    log_info "Debian/Ubuntu 驱动安装完成。"
}

# 清理输入中的控制字符（防止终端退格等干扰）
clean_input() {
    printf '%s' "$1" | tr -d '\000-\010\013\014\016-\037'
}

# CIDR 转子网掩码
cidr_to_netmask() {
    local cidr="$1"
    local full_octets=$((cidr / 8))
    local partial_octet=$((cidr % 8))
    local mask=""
    for ((i=0; i<4; i++)); do
        if [[ $i -lt $full_octets ]]; then
            mask+="255"
        elif [[ $i -eq $full_octets ]]; then
            mask+=$((256 - 2**(8-partial_octet)))
        else
            mask+="0"
        fi
        [[ $i -lt 3 ]] && mask+="."
    done
    echo "$mask"
}

# 检测网络管理方式
detect_network_backend() {
    if [[ -d /etc/netplan ]]; then
        echo "netplan"
    elif [[ -f /etc/network/interfaces ]]; then
        echo "ifupdown"
    elif [[ -d /etc/sysconfig/network-scripts ]]; then
        echo "ifcfg"
    else
        echo "netplan"
    fi
}

# 检测网卡名称
detect_iface() {
    local iface=""
    for item in /sys/class/net/*; do
        local name
        name=$(basename "$item")
        if [[ "$name" != "lo" ]]; then
            iface="$name"
            break
        fi
    done
    echo "$iface"
}

# 交互式网络配置
interactive_network() {
    echo ""
    log_step "网络配置向导"
    echo -e "请输入静态 IP 信息（${YELLOW}直接回车可跳过网络配置${NC}）"
    echo ""

    read -rp "IP地址/掩码前缀 (示例: 192.168.1.100/24): " IP_CIDR
    IP_CIDR=$(clean_input "$IP_CIDR")
    [[ -z "$IP_CIDR" ]] && { log_info "跳过网络配置"; return 1; }

    # 解析 IP 和掩码
    IPADDR="${IP_CIDR%/*}"
    local cidr="${IP_CIDR#*/}"
    NETMASK=$(cidr_to_netmask "$cidr")

    read -rp "网关地址 (示例: 192.168.1.1):     " GATEWAY
    GATEWAY=$(clean_input "$GATEWAY")
    read -rp "首选DNS (示例: 223.5.5.5):       " DNS1
    DNS1=$(clean_input "$DNS1")
    read -rp "备用DNS (示例: 223.6.6.6):       " DNS2
    DNS2=$(clean_input "$DNS2")

    echo ""
    echo -e "${CYAN}┌────────────────────────────────────────${NC}"
    echo -e "${CYAN}│${NC} 配置汇总"
    echo -e "${CYAN}├────────────────────────────────────────${NC}"
    echo -e "${CYAN}│${NC}  IP地址:   ${BOLD}$IPADDR${NC}"
    echo -e "${CYAN}│${NC}  子网掩码: ${BOLD}$NETMASK${NC}"
    echo -e "${CYAN}│${NC}  网关:     ${BOLD}$GATEWAY${NC}"
    echo -e "${CYAN}│${NC}  DNS1:     ${BOLD}$DNS1${NC}"
    echo -e "${CYAN}│${NC}  DNS2:     ${BOLD}$DNS2${NC}"
    echo -e "${CYAN}└────────────────────────────────────────${NC}"
    echo ""
    read -rp "确认以上配置? [Y/n]: " confirm
    if [[ "$confirm" =~ ^[Nn]$ ]]; then
        log_info "取消网络配置"
        return 1
    fi
    return 0
}

# 写入 CentOS ifcfg 配置
write_ifcfg() {
    local dev="$1"
    local cfg_file="/etc/sysconfig/network-scripts/ifcfg-$dev"
    mkdir -p /etc/sysconfig/network-scripts
    printf '%s\n' \
        'TYPE="Ethernet"' \
        'BOOTPROTO="static"' \
        'DEFROUTE="yes"' \
        'IPV4_FAILURE_FATAL="no"' \
        'IPV6INIT="no"' \
        'ONBOOT="yes"' \
        "DEVICE=\"$dev\"" \
        "NAME=\"$dev\"" \
        "IPADDR=\"$IPADDR\"" \
        "NETMASK=\"$NETMASK\"" \
        "GATEWAY=\"$GATEWAY\"" \
        "DNS1=\"$DNS1\"" \
        "DNS2=\"$DNS2\"" > "$cfg_file"
}

# 写入 netplan 配置
write_netplan() {
    local dev="$1"
    local yaml_file="/etc/netplan/01-r8125-static.yaml"
    mkdir -p /etc/netplan

    # Ubuntu 24.04 / Debian 12+ 使用 routes，旧版本使用 gateway4
    if [[ ("$OS_FAMILY" == "ubuntu" && "$OS_VER_ID" == "24.04") || \
          ("$OS_FAMILY" == "debian" && ("$OS_VER_ID" == "12" || "$OS_VER_ID" == "13")) ]]; then
        printf '%s\n' \
            'network:' \
            '  version: 2' \
            '  renderer: networkd' \
            '  ethernets:' \
            "    $dev:" \
            '      addresses:' \
            "        - $IP_CIDR" \
            '      routes:' \
            '        - to: default' \
            "          via: $GATEWAY" \
            '      nameservers:' \
            '        addresses:' \
            "          - $DNS1" \
            "          - $DNS2" > "$yaml_file"
    else
        printf '%s\n' \
            'network:' \
            '  version: 2' \
            '  renderer: networkd' \
            '  ethernets:' \
            "    $dev:" \
            '      addresses:' \
            "        - $IP_CIDR" \
            "      gateway4: $GATEWAY" \
            '      nameservers:' \
            '        addresses:' \
            "          - $DNS1" \
            "          - $DNS2" > "$yaml_file"
    fi
    chmod 600 "$yaml_file"
}

# 写入 ifupdown 配置
write_ifupdown() {
    local dev="$1"
    printf '%s\n' \
        'source /etc/network/interfaces.d/*' \
        '' \
        'auto lo' \
        'iface lo inet loopback' \
        '' \
        "auto $dev" \
        "iface $dev inet static" \
        "    address $IPADDR" \
        "    netmask $NETMASK" \
        "    gateway $GATEWAY" \
        "    dns-nameservers $DNS1 $DNS2" > "/etc/network/interfaces"

    printf '%s\n' \
        "nameserver $DNS1" \
        "nameserver $DNS2" > "/etc/resolv.conf"
}

# 处理可能存在的 cloud-init 或其他 netplan 配置
handle_existing_netplan() {
    local cloud_init="/etc/netplan/50-cloud-init.yaml"
    if [[ -f "$cloud_init" ]]; then
        echo ""
        log_warn "检测到已存在 netplan 配置文件: 50-cloud-init.yaml"
        log_warn "该文件通常包含 cloud-init 或 USB 网卡的临时网络配置。"
        log_warn "如果保留该文件，拔掉 USB 网卡后重启可能会导致 netplan 报错或路由冲突。"
        read -rp "是否备份并禁用 50-cloud-init.yaml? [Y/n]: " disable_choice
        if [[ ! "$disable_choice" =~ ^[Nn]$ ]]; then
            local backup_name="${cloud_init}.bak.$(date +%Y%m%d%H%M%S)"
            mv "$cloud_init" "$backup_name"
            log_info "已备份并禁用: $backup_name"
        else
            log_warn "已保留 50-cloud-init.yaml，如果后续出现网络冲突请手动处理。"
        fi
    fi
}

# 应用网络配置
apply_network() {
    local backend="$1"
    case "$backend" in
        netplan)
            chmod 600 /etc/netplan/01-r8125-static.yaml
            netplan apply
            ;;
        ifupdown)
            systemctl restart networking 2>/dev/null || service networking restart 2>/dev/null || true
            ;;
        ifcfg)
            systemctl restart NetworkManager 2>/dev/null || true
            ;;
    esac
}

# 检测桌面环境
check_desktop_env() {
    local has_desktop=0
    local desktop_info=""

    # 检查显示管理器服务
    for dm in gdm gdm3 sddm lightdm lxdm xdm; do
        if systemctl is-enabled "$dm" &>/dev/null || systemctl is-active "$dm" &>/dev/null; then
            has_desktop=1
            desktop_info="$desktop_info $dm"
        fi
    done

    # 检查常见桌面包
    case "$OS_FAMILY" in
        centos)
            if rpm -qa 2>/dev/null | grep -qiE "gnome-desktop|kde-desktop|xfce-desktop|mate-desktop|cinnamon-desktop"; then
                has_desktop=1
            fi
            ;;
        ubuntu|debian)
            if dpkg -l 2>/dev/null | grep -qE "gnome-desktop|kde-desktop|xfce4|mate-desktop|cinnamon-desktop"; then
                has_desktop=1
            fi
            ;;
    esac

    # 检查 Xorg
    if [[ -f /usr/bin/Xorg ]] || [[ -f /usr/bin/X ]]; then
        has_desktop=1
    fi

    if [[ "$has_desktop" == "1" ]]; then
        echo ""
        log_warn "========================================"
        log_warn "  检测到当前系统安装了桌面环境"
        if [[ -n "$desktop_info" ]]; then
            log_warn "  显示管理器:$desktop_info"
        fi
        log_warn "========================================"
        log_warn "生产服务器建议使用最小化安装以获得最佳稳定性。"
        echo ""
    else
        log_info "系统目前是最小化安装，没有配置桌面环境。"
    fi
}

# 检测 SSH root 密码登录状态
check_ssh_root_login() {
    if [[ ! -f /etc/ssh/sshd_config ]]; then
        log_warn "未找到 /etc/ssh/sshd_config，跳过 SSH 检测。"
        return
    fi

    local permit_root=""
    local password_auth=""

    # 读取主配置中的有效配置行（非注释）
    permit_root=$(grep -i "^PermitRootLogin" /etc/ssh/sshd_config | awk '{print $2}' | tail -1) || true
    password_auth=$(grep -i "^PasswordAuthentication" /etc/ssh/sshd_config | awk '{print $2}' | tail -1) || true

    # 如果主配置中没有，检查 Include 引入的子配置
    if [[ -z "$permit_root" ]] && grep -q "Include.*/sshd_config.d" /etc/ssh/sshd_config 2>/dev/null; then
        if [[ -d /etc/ssh/sshd_config.d ]]; then
            permit_root=$(grep -ri "^PermitRootLogin" /etc/ssh/sshd_config.d/ 2>/dev/null | awk '{print $2}' | tail -1) || true
        fi
    fi
    if [[ -z "$password_auth" ]] && grep -q "Include.*/sshd_config.d" /etc/ssh/sshd_config 2>/dev/null; then
        if [[ -d /etc/ssh/sshd_config.d ]]; then
            password_auth=$(grep -ri "^PasswordAuthentication" /etc/ssh/sshd_config.d/ 2>/dev/null | awk '{print $2}' | tail -1) || true
        fi
    fi

    # OpenSSH 7+ 默认值
    [[ -z "$permit_root" ]] && permit_root="prohibit-password"
    [[ -z "$password_auth" ]] && password_auth="yes"

    local need_fix=0
    local issue_msg=""

    if [[ "$permit_root" != "yes" ]]; then
        need_fix=1
        issue_msg="${issue_msg}  PermitRootLogin = ${permit_root}\n"
    fi
    if [[ "$password_auth" != "yes" ]]; then
        need_fix=1
        issue_msg="${issue_msg}  PasswordAuthentication = ${password_auth}\n"
    fi

    if [[ "$need_fix" == "1" ]]; then
        echo ""
        log_warn "========================================"
        log_warn "  检测到 SSH root 密码登录未完全开启"
        log_warn "========================================"
        echo -e "${YELLOW}当前配置:${NC}"
        echo -e "${issue_msg}"
        read -rp "是否开启 root 用户 SSH 远程密码登录? [y/N]: " ssh_choice
        if [[ "$ssh_choice" =~ ^[Yy]$ ]]; then
            configure_ssh
            log_info "SSH 服务已重启，配置已生效。"
        else
            log_info "已跳过 SSH 配置修改。"
        fi
    else
        log_info "SSH root 密码登录已处于开启状态，无需修改。"
    fi
}

# 配置 SSH
configure_ssh() {
    if [[ -f /etc/ssh/sshd_config ]]; then
        sed -i 's/^#*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
        sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
        systemctl restart sshd 2>/dev/null || service ssh restart 2>/dev/null || true
    fi
}

# 主流程
main() {
    check_root
    check_commands

    if [[ -z "$BASE_URL" ]]; then
        echo ""
        log_error "请先在脚本中设置 BASE_URL 变量为你的文件服务器地址。"
        echo ""
        echo -e "示例: ${BOLD}BASE_URL=\"http://192.168.1.100/drivers\"${NC}"
        echo ""
        echo "服务器目录结构要求:"
        echo "  \${BASE_URL}/centos/r8125-kmod-<ver>-1.el<X_Y>.elrepo.rpm"
        echo "  \${BASE_URL}/debian_ubuntu/realtek-r8125-dkms_<ver>-1_amd64.deb"
        echo ""
        exit 1
    fi

    detect_os
    check_desktop_env

    echo ""
    echo -e "${CYAN}========================================${NC}"
    echo -e "${CYAN}  R8125 网卡驱动自动安装工具by豆芽${NC}"
    echo -e "${CYAN}========================================${NC}"
    echo -e "  系统: ${BOLD}$OS_ID $OS_VER_ID${NC}"
    echo -e "  内核: ${BOLD}$(uname -r)${NC}"
    echo -e "  模式: ${BOLD}$([ "${OFFLINE_MODE}" == "1" ] && echo "离线" || echo "在线")${NC}"
    echo -e "${CYAN}========================================${NC}"
    echo ""

    read -rp "确认开始安装驱动? [Y/n]: " confirm
    [[ "$confirm" =~ ^[Nn]$ ]] && { log_info "已取消安装。"; exit 0; }

    # 安装驱动
    case "$OS_FAMILY" in
        centos)
            install_centos
            ;;
        ubuntu|debian)
            install_debian_ubuntu
            ;;
    esac

    # 加载驱动并检测网卡
    log_step "加载 r8125 驱动模块..."
    modprobe r8125 || true
    sleep 2

    IFACE=$(detect_iface)
    if [[ -z "$IFACE" ]]; then
        log_warn "未检测到除 lo 外的网络接口，可能驱动尚未生效或没有 R8125 网卡。"
    else
        log_info "检测到网卡接口: ${BOLD}$IFACE${NC}"
    fi

    # 交互式网络配置
    if interactive_network; then
        local backend
        backend=$(detect_network_backend)
        log_info "网络管理方式: ${BOLD}$backend${NC}"

        case "$backend" in
            netplan)
                write_netplan "$IFACE"
                handle_existing_netplan
                ;;
            ifupdown)
                write_ifupdown "$IFACE"
                ;;
            ifcfg)
                write_ifcfg "$IFACE"
                ;;
        esac

        log_info "网络配置已写入，将在重启后生效（避免当前USB网卡临时连接中断）。"
    fi

    # SSH 检测与配置
    check_ssh_root_login

    echo ""
    log_info "驱动安装与配置全部完成。"
    log_info "网络配置和驱动将在重启后生效。"
    read -rp "是否立即重启服务器使配置生效? [Y/n]: " reboot_confirm
    if [[ ! "$reboot_confirm" =~ ^[Nn]$ ]]; then
        log_info "系统将在 5 秒后重启..."
        sleep 5
        reboot
    else
        log_info "请稍后手动重启服务器，以使驱动和网络配置完全生效。"
    fi
}

main "$@"
