#!/usr/bin/env bash

#====================================================
# OpenWrt 构建管理脚本
# 功能：提供交互式菜单，可选择执行特定操作
# 更新：2025-04-05
#====================================================

#---------------基础配置---------------#
# 日志目录设置
LOGS_ROOT="openwrt_logs"
SESSION_DIR="${LOGS_ROOT}/$(date +%Y%m%d_%H%M%S)"
LOG_FILE="${SESSION_DIR}/main_build_script.log" # 主脚本日志文件名更改，更清晰

#---------------清理配置---------------#
# 需要移除的目录列表 (示例，根据你的需要添加)
declare -a REMOVE_DIRS=(
    # "feeds/packages/net/v2ray-geodata" # 示例
)

# 需要移除的包列表 (示例，根据你的需要添加)
declare -a REMOVE_PACKAGES=(
    # "package/feeds/luci/luci-app-example" # 示例
)

#---------------自定义包配置---------------#
# 定义自定义包配置，格式：[包名]=[目标目录]=[仓库URL]=[分支]=[是否使用--depth 1]
declare -A CUSTOM_PACKAGES=(
    ["partexp"]="package/luci-app-partexp=https://github.com/sirpdboy/luci-app-partexp=main=false"
    ["openclash"]="package/openclash=https://github.com/vernesong/OpenClash=dev=true"
    ["zerotier"]="package/luci-app-zerotier=https://github.com/Firsgith/luci-app-zerotier.git=main=false"
    # ["5gsupport"]="package/5G-Modem-Support=https://nanako.site/gitea/Nanako/openwrt-app-actions.git=main=false"
    # ["pcat"]="package/pcat-manager=https://github.com/photonicat/rockchip_rk3568_pcat_manager.git=master=true"
)

#---------------日志系统---------------#
# 保存原始的标准输出和错误输出文件描述符
exec {STDOUT_ORIG}>&1
exec {STDERR_ORIG}>&2

# 全局变量标记日志是否启用
LOGGING_ENABLED=false # 初始为 false，由 init_logger 启用

# 初始化日志系统
init_logger() {
    # 创建日志目录结构
    mkdir -p "$SESSION_DIR" || {
        echo "错误: 无法创建日志目录: $SESSION_DIR" >&2
        exit 1
    }

    LOGGING_ENABLED=true
    echo "日志将保存在: $SESSION_DIR"
    echo "主脚本日志: $LOG_FILE"

    # 重定向主脚本的 stdout 和 stderr 到 tee，同时输出到控制台和主日志文件
    # 使用 process substitution 和 tee
    exec > >(tee -a "$LOG_FILE")
    exec 2> >(tee -a "$LOG_FILE" >&2)

    # 记录初始信息到日志
    echo "[$(date "+%Y-%m-%d %H:%M:%S")] [INFO]: 日志系统初始化完成。主日志文件: $LOG_FILE"
}

# 创建新的特定构建阶段的日志文件
create_build_log() {
    local build_type=$1
    local timestamp=$(date +%Y%m%d_%H%M%S)
    # 使用更明确的文件名
    BUILD_LOG_FILE="${SESSION_DIR}/${build_type}_build_${timestamp}.log"
    # 确保文件被创建，即使命令没有输出
    touch "$BUILD_LOG_FILE" || {
        log "ERROR" "无法创建构建日志文件: $BUILD_LOG_FILE"
        return 1
    }
    # 返回创建的日志文件名
    echo "$BUILD_LOG_FILE"
    return 0
}

# 禁用日志重定向 (用于 menuconfig 等交互场景)
disable_logging() {
    if [ "$LOGGING_ENABLED" = true ]; then
        log "DEBUG" "禁用日志重定向，恢复原始标准输出/错误。"
        exec >&$STDOUT_ORIG
        exec 2>&$STDERR_ORIG
        LOGGING_ENABLED=false # 标记为禁用
    fi
}

# 启用日志重定向 (恢复)
enable_logging() {
    # 仅在之前被禁用的情况下才重新启用
    if [ "$LOGGING_ENABLED" = false ]; then
        # 重新应用重定向到主日志
        exec > >(tee -a "$LOG_FILE")
        exec 2> >(tee -a "$LOG_FILE" >&2)
        LOGGING_ENABLED=true # 标记为启用
        log "DEBUG" "重新启用日志重定向到主日志。"
    fi
}

# 设置终端颜色
setup_colors() {
    if [[ -t 1 ]]; then # 检查标准输出是否连接到终端
        RED='\033[0;31m'
        GREEN='\033[0;32m'
        YELLOW='\033[1;33m'
        BLUE='\033[0;34m'
        NC='\033[0m' # No Color
    else
        RED='' GREEN='' YELLOW='' BLUE='' NC=''
    fi
}

# 记录日志函数 - 使用此函数来明确日志级别
# 注意：此函数输出会经过 init_logger 设置的全局重定向
log() {
    local level=$1
    local message=$2
    local timestamp
    timestamp=$(date "+%Y-%m-%d %H:%M:%S")
    local color="" level_str=""

    case $level in
        "INFO")  color="$GREEN";  level_str="INFO " ;; # 加空格对齐
        "WARN")  color="$YELLOW"; level_str="WARN " ;;
        "ERROR") color="$RED";    level_str="ERROR" ;;
        "DEBUG") color="$BLUE";   level_str="DEBUG" ;;
        *)       color="";        level_str="LOG  " ;; # 默认级别
    esac

    # 使用 printf 保证原子写入，减少并发问题
    printf "[%s] %b[%s]%b: %s\n" "$timestamp" "$color" "$level_str" "$NC" "$message"
}

# 同时记录消息到主日志和特定的构建日志
log_to_both() {
    local level=$1
    local message=$2
    local build_log_file=$3 # 明确参数名

    # 1. 输出到主日志（通过全局重定向和 log 函数）
    log "$level" "$message"

    # 2. 追加到指定的构建日志文件
    local timestamp
    timestamp=$(date "+%Y-%m-%d %H:%M:%S")
    # 直接追加，不需要颜色代码
    printf "[%s] [%s]: %s\n" "$timestamp" "$level" "$message" >> "$build_log_file"
}


#---------------自定义包管理函数---------------#
# 更新单个自定义包
update_single_package() {
    local pkg_name=$1
    local config=$2

    # 解析配置 (保持 cut 的方式，假设路径/URL/分支名不含 '=')
    # 如果遇到问题，可以切换到 IFS/read
    local target_dir repo_url branch use_depth
    target_dir=$(echo "$config" | cut -d= -f1)
    repo_url=$(echo "$config" | cut -d= -f2)
    branch=$(echo "$config" | cut -d= -f3)
    use_depth=$(echo "$config" | cut -d= -f4)

    # 基础验证
    if [ -z "$target_dir" ] || [ -z "$repo_url" ]; then
        log "ERROR" "包 '$pkg_name' 的配置无效: $config"
        return 1
    fi

    log "INFO" "更新自定义包: $pkg_name..."

    # 检查目标目录的父目录是否存在
    local parent_dir
    parent_dir=$(dirname "$target_dir")
    if [ ! -d "$parent_dir" ]; then
        log "INFO" "创建父目录: $parent_dir"
        mkdir -p "$parent_dir" || {
            log "ERROR" "无法创建父目录: $parent_dir"
            return 1
        }
    fi

    # 移除现有目录
    if [ -d "$target_dir" ]; then
        log "INFO" "移除现有目录: $target_dir"
        rm -rf "$target_dir" || {
            log "ERROR" "无法删除目录: $target_dir"
            return 1
        }
    fi

    # 准备 git clone 命令参数数组 (移除 eval)
    local git_options=("--progress") # 总是显示进度
    # 处理分支
    if [ -n "$branch" ] && [ "$branch" != "master" ]; then
        git_options+=("-b" "$branch")
    fi
    # 处理 depth
    if [ "$use_depth" = "true" ]; then
        git_options+=("--depth" "1")
    fi

    # 执行克隆
    log "INFO" "执行: git clone ${git_options[*]} $repo_url $target_dir"
    if git clone "${git_options[@]}" "$repo_url" "$target_dir"; then
        log "INFO" "包 '$pkg_name' 更新成功"
        return 0
    else
        log "ERROR" "克隆包 '$pkg_name' 失败 (仓库: $repo_url)"
        # 尝试给出更具体的错误提示
        log "ERROR" "请检查网络连接、仓库 URL、分支名称以及目标目录权限。"
        # 保留可能存在的空目录或部分克隆，让用户检查
        # rm -rf "$target_dir" # 不再自动删除失败的克隆
        return 1
    fi
}

# 更新所有自定义包的主函数
update_custom_package() {
    local failed_packages=()
    local success_count=0
    local total_packages=${#CUSTOM_PACKAGES[@]}

    if [ "$total_packages" -eq 0 ]; then
        log "INFO" "没有配置自定义包，跳过更新。"
        return 0
    fi

    log "INFO" "开始更新 $total_packages 个自定义包..."

    for pkg_name in "${!CUSTOM_PACKAGES[@]}"; do
        # 使用 subshell 执行，避免污染当前环境的变量，但这里影响不大
        if update_single_package "$pkg_name" "${CUSTOM_PACKAGES[$pkg_name]}"; then
             ((success_count++))
        else
            failed_packages+=("$pkg_name")
        fi
    done

    # 显示更新结果
    if [ ${#failed_packages[@]} -eq 0 ]; then
        log "INFO" "所有自定义包更新成功 ($success_count/$total_packages)"
        return 0
    else
        log "WARN" "部分自定义包更新失败 (成功: $success_count/$total_packages)"
        log "ERROR" "更新失败的包: ${failed_packages[*]}"
        return 1 # 返回失败状态码
    fi
}

# 更新特定自定义包
update_specific_package() {
    local pkg_name=$1

    if [ -z "$pkg_name" ]; then
        log "ERROR" "未指定包名"
        return 1
    fi

    if [ -z "${CUSTOM_PACKAGES[$pkg_name]}" ]; then
        log "ERROR" "未找到包配置：'$pkg_name'"
        log "INFO" "可用的包名: ${!CUSTOM_PACKAGES[*]}"
        return 1
    fi

    update_single_package "$pkg_name" "${CUSTOM_PACKAGES[$pkg_name]}"
}

#---------------基础功能函数---------------#
# 清理工作区 (make clean 的替代方案，更彻底)
clean_workspace() {
    log "INFO" "开始彻底清理工作区..."

    # 清理 feeds (可选，如果 feeds 内容经常变动或出问题可以启用)
    # log "INFO" "执行 ./scripts/feeds clean ..."
    # ./scripts/feeds clean || log "WARN" "./scripts/feeds clean 执行时遇到问题。"

    # 清理编译产物和临时文件
    log "INFO" "执行 rm -rf ./tmp ./logs ./staging_dir ./build_dir ./bin ./dl ..."
    # 注意：这里移除了 logs 目录，但我们的脚本日志在 openwrt_logs 下，不会被删
    # 如果 OpenWrt 自身有 logs 目录且需要保留，则从下面移除 ./logs
    rm -rf ./tmp ./logs ./staging_dir ./build_dir ./bin ./dl || {
        log "ERROR" "删除部分工作区目录失败，请检查权限或文件占用。"
        return 1
    }

    log "INFO" "工作区清理完成。"
    return 0
}

# 清理编译临时文件 (make clean 的快速版)
clean_build_temp() {
    log "INFO" "开始清理编译临时文件..."

    log "INFO" "执行 rm -rf ./tmp ./staging_dir ./build_dir ..."
    rm -rf ./tmp ./staging_dir ./build_dir || {
         log "ERROR" "删除部分编译临时目录失败。"
         return 1
    }

    log "INFO" "编译临时文件清理完成。"
    return 0
}

# 更新源码
update_source() {
    log "INFO" "开始更新 OpenWrt 源码 (git pull)..."
    if git pull --rebase; then # 使用 rebase 避免不必要的 merge commit
        log "INFO" "源码更新完成"
        return 0
    else
        log "ERROR" "源码更新失败 (git pull --rebase)"
        log "WARN" "请检查本地是否有未提交的修改，或尝试手动解决 Git 冲突。"
        return 1
    fi
}

# 更新并安装 feeds
update_feeds() {
    log "INFO" "开始更新 Feeds (update -a)..."
    if ./scripts/feeds update -a; then
        log "INFO" "Feeds 更新成功，开始安装 (install -a)..."
        if ./scripts/feeds install -a; then
            log "INFO" "Feeds 安装成功"
            return 0
        else
            log "ERROR" "Feeds 安装失败 (install -a)"
            return 1
        fi
    else
        log "ERROR" "Feeds 更新失败 (update -a)"
        return 1
    fi
}

# 执行构建相关命令，并将 stdout 重定向到日志，stderr 同时输出到控制台和日志
run_build_command() {
    local cmd=$1              # 要执行的命令字符串
    local log_file=$2         # 目标日志文件
    local description=$3      # 操作描述

    log_to_both "INFO" "开始执行: $description" "$log_file"
    log "DEBUG" "命令详情: $cmd" # 只记录到主日志

    # 执行命令
    # stdout (>>) 追加到日志文件
    # stderr (2>) 通过管道给 tee
    #   tee -a "$log_file" 将 stderr 追加到日志文件
    #   tee 默认将其标准输入复制到标准输出，这里即脚本的 stderr，因此会显示在控制台
    local start_time end_time duration
    start_time=$(date +%s)
    if eval "$cmd" >> "$log_file" 2> >(tee -a "$log_file" >&2); then
        end_time=$(date +%s)
        duration=$((end_time - start_time))
        log_to_both "INFO" "$description 完成 (耗时: ${duration}s)" "$log_file"
        return 0 # 成功返回 0
    else
        end_time=$(date +%s)
        duration=$((end_time - start_time))
        local exit_code=$? # 获取命令的退出码
        # 错误信息已经通过 stderr 的 tee 输出到控制台了
        log_to_both "ERROR" "$description 失败 (退出码: $exit_code, 耗时: ${duration}s)" "$log_file"
        log "ERROR" "详细错误请查看控制台输出以及日志文件: $log_file"
        return $exit_code # 失败返回命令的退出码
    fi
}

# 编译固件
build_firmware() {
    # 创建新的固件编译日志文件
    local current_log
    current_log=$(create_build_log "firmware") || return 1 # 创建失败则退出

    log "INFO" "开始编译固件..."
    log "INFO" "详细编译日志将保存在: $current_log"

    # 1. 下载依赖包
    local download_cmd="make download -j$(nproc) V=s"
    run_build_command "$download_cmd" "$current_log" "下载依赖包" || {
        log "ERROR" "依赖包下载失败，编译中止。"
        # 即使下载失败，日志文件也已包含错误信息
        return 1
    }

    # 2. 多线程编译
    local cpu_cores
    cpu_cores=$(nproc)
    log "INFO" "检测到 $cpu_cores 个 CPU 核心，开始多线程编译..."
    local build_cmd="make -j${cpu_cores} V=s"

    if run_build_command "$build_cmd" "$current_log" "固件编译 (多线程)"; then
        log "INFO" "${GREEN}固件编译成功完成！${NC}"
        log "INFO" "固件输出目录: ./bin/targets/"
        return 0 # 编译成功
    else
        # 多线程编译失败，询问用户是否重试
        log "WARN" "多线程编译失败。"
        local retry_choice
        # -r: raw input, -p: prompt, -n 1: read only one char (optional but nice), -t 15: timeout (optional)
        # Default to No
        read -rp "$(echo -e ${YELLOW}"是否尝试使用单线程重新编译? (y/N): "${NC})" -n 1 -t 30 retry_choice
        echo # Add a newline after read -n

        if [[ "$retry_choice" =~ ^[Yy]$ ]]; then
            log "INFO" "用户选择使用单线程重试编译..."

            # 3. 单线程编译重试
            local build_cmd_single="make -j1 V=s"
            if run_build_command "$build_cmd_single" "$current_log" "固件编译 (单线程重试)"; then
                log "INFO" "${GREEN}单线程编译成功完成！${NC}"
                log "INFO" "固件输出目录: ./bin/targets/"
                return 0 # 单线程编译成功
            else
                log "ERROR" "${RED}单线程编译也失败了。${NC}"
                log "ERROR" "请仔细检查控制台错误输出以及日志文件: $current_log"
                return 1 # 最终编译失败
            fi
        else
            log "INFO" "用户选择不进行单线程重试编译。"
            log "ERROR" "${RED}编译失败，未进行单线程重试。${NC}"
            log "ERROR" "请仔细检查控制台错误输出以及日志文件: $current_log"
            return 1 # 用户取消重试，编译失败
        fi
    fi
}

# 清理配置文件中指定的旧包/目录
clean_packages() {
    log "INFO" "开始清理配置文件中指定的旧包和目录..."
    local removed_count=0
    local failed_count=0
    local total_to_remove=$((${#REMOVE_DIRS[@]} + ${#REMOVE_PACKAGES[@]}))

    if [ "$total_to_remove" -eq 0 ]; then
        log "INFO" "配置文件中未指定需要移除的包或目录。"
        return 0
    fi

    # 清理目录
    for dir in "${REMOVE_DIRS[@]}"; do
        if [ -e "$dir" ]; then # 使用 -e 检查文件或目录是否存在
            log "INFO" "正在删除目录: $dir"
            if rm -rf "$dir"; then
                log "INFO" "已删除: $dir"
                ((removed_count++))
            else
                log "ERROR" "删除失败: $dir (请检查权限或是否被占用)"
                ((failed_count++))
            fi
        else
             log "WARN" "指定的目录不存在，跳过: $dir"
        fi
    done

    # 清理包 (通常包也是目录)
    for pkg in "${REMOVE_PACKAGES[@]}"; do
         if [ -e "$pkg" ]; then
            log "INFO" "正在删除包/目录: $pkg"
            if rm -rf "$pkg"; then
                log "INFO" "已删除: $pkg"
                ((removed_count++))
            else
                log "ERROR" "删除失败: $pkg (请检查权限或是否被占用)"
                ((failed_count++))
            fi
        else
             log "WARN" "指定的包/目录不存在，跳过: $pkg"
        fi
    done

    if [ $failed_count -eq 0 ]; then
        log "INFO" "旧包/目录清理完成，共处理 $removed_count 个项目。"
        return 0
    else
        log "WARN" "旧包/目录清理部分完成 (成功: $removed_count, 失败: $failed_count)"
        return 1 # 返回失败状态码
    fi
}

# 更新所有组件 (源码 -> 清理旧包 -> 自定义包 -> feeds)
update_all_components() {
    log "INFO" "开始更新所有组件..."
    local success=true # 假设成功

    # 1. 更新源码
    log "INFO" "[1/4] 更新 OpenWrt 源码..."
    update_source || success=false

    # 2. 清理旧包 (即使上一步失败也尝试清理)
    log "INFO" "[2/4] 清理配置文件指定的旧包/目录..."
    clean_packages || log "WARN" "清理旧包/目录时遇到问题，继续执行..." # 清理失败通常不阻止后续

    # 3. 更新自定义包 (只有在源码更新成功时才执行较好)
    if [ "$success" = true ]; then
        log "INFO" "[3/4] 更新自定义包..."
        update_custom_package || success=false
    else
        log "WARN" "[3/4] 跳过更新自定义包，因为源码更新失败。"
    fi

    # 4. 更新 Feeds (只有在源码和自定义包都成功时执行较好)
    if [ "$success" = true ]; then
        log "INFO" "[4/4] 更新 Feeds..."
        update_feeds || success=false
    else
        log "WARN" "[4/4] 跳过更新 Feeds，因为之前的步骤失败。"
    fi

    # 总结
    if [ "$success" = true ]; then
        log "INFO" "所有组件更新完成！"
        return 0
    else
        log "ERROR" "部分或全部组件更新失败，请检查上面的日志。"
        return 1
    fi
}

# 菜单配置 (make menuconfig)
menuconfig() {
    log "INFO" "准备进入菜单配置 (make menuconfig)..."
    log "INFO" "注意：日志重定向将暂时禁用以进行交互。"

    # 禁用日志重定向，否则 menuconfig 界面可能显示不正常
    disable_logging

    # 执行 menuconfig
    if make menuconfig; then
        # 配置成功后重新启用日志
        enable_logging
        log "INFO" "菜单配置完成。新配置已保存到 .config"
        # 询问是否保存 defconfig (可选)
        # read -p "是否将当前配置保存为 defconfig? (y/N): " save_defconfig
        # if [[ "$save_defconfig" =~ ^[Yy]$ ]]; then
        #     ./scripts/diffconfig.sh > my_defconfig
        #     log "INFO" "当前配置已保存到 my_defconfig"
        # fi
        return 0
    else
        # 配置失败或被取消，也要恢复日志
        enable_logging
        log "WARN" "菜单配置未完成或被取消。"
        return 1 # 返回失败状态码
    fi
}

#---------------组合功能函数---------------#
# 完整构建流程
full_build() {
    log "INFO" "启动完整构建流程..."
    local step=1
    local total_steps=6 # 预估步骤数

    # 1. 清理工作区
    log "INFO" "[${step}/${total_steps}] 清理工作区..."
    clean_workspace || { log "WARN" "工作区清理可能不完整，尝试继续..."; } # 清理失败通常不致命
    ((step++))

    # 2. 更新源码
    log "INFO" "[${step}/${total_steps}] 更新源码..."
    update_source || { log "ERROR" "源码更新失败，终止构建流程。"; return 1; }
    ((step++))

    # 3. 清理旧包
    log "INFO" "[${step}/${total_steps}] 清理配置文件指定的旧包..."
    clean_packages || log "WARN" "清理旧包时遇到问题，继续执行..."
    ((step++))

    # 4. 更新自定义包
    log "INFO" "[${step}/${total_steps}] 更新自定义包..."
    update_custom_package || { log "ERROR" "自定义包更新失败，终止构建流程。"; return 1; }
    ((step++))

    # 5. 更新 Feeds
    log "INFO" "[${step}/${total_steps}] 更新 Feeds..."
    update_feeds || { log "ERROR" "Feeds 更新失败，终止构建流程。"; return 1; }
    ((step++))

    # 6. 菜单配置
    log "INFO" "[${step}/${total_steps}] 进入菜单配置 (make menuconfig)..."
    menuconfig || { log "WARN" "菜单配置未完成或取消，但继续尝试编译..."; } # 允许使用现有配置编译
    ((step++)) # 无论成功与否，都算一步

    # 7. 编译固件 (独立步骤，不计入前面的 total_steps)
    log "INFO" "所有准备工作完成，开始编译固件..."
    if build_firmware; then
        log "INFO" "${GREEN}完整构建流程成功完成！${NC}"
        return 0
    else
        log "ERROR" "${RED}完整构建流程失败于编译阶段。${NC}"
        return 1
    fi
}

#---------------菜单函数---------------#
# 打印主菜单
print_menu() {
    echo -e "\n${BLUE}======= OpenWrt 构建管理菜单 =======${NC}"
    echo -e " ${YELLOW}会话日志目录: ${SESSION_DIR}${NC}"
    echo -e "${GREEN} 1.${NC} ${BOLD}完整构建流程${NC} (清理 > 更新源码/包/feeds > 配置 > 编译)"
    echo -e "${GREEN} 2.${NC} 清理工作区 (删除 tmp, bin, build_dir 等)"
    echo -e "${GREEN} 3.${NC} 更新所有组件 (源码 + 旧包清理 + 自定义包 + feeds)"
    echo -e "${GREEN} 4.${NC} 清理配置文件指定的旧包/目录"
    echo -e "${GREEN} 5.${NC} ${BOLD}编译固件${NC} (make V=s)"
    echo -e "${GREEN} 6.${NC} 调整配置 (make menuconfig)"
    echo -e "${GREEN} 7.${NC} 更新所有自定义包"
    echo -e "${GREEN} 8.${NC} 更新特定的自定义包"
    echo -e "${GREEN} 9.${NC} 更新 OpenWrt 源码 (git pull)"
    echo -e "${GREEN}10.${NC} 更新并安装 Feeds"
    echo -e "-------------------------------------"
    echo -e "${GREEN} 0.${NC} 退出脚本"
    echo -e "${BLUE}====================================${NC}"
    # 使用 read -p 提供提示
    read -rp "请输入选项 [0-10]: " choice
}

# 打印并选择特定自定义包进行更新
select_specific_package() {
    local pkg_names=("${!CUSTOM_PACKAGES[@]}") # 获取所有包名
    local num_packages=${#pkg_names[@]}

    if [ "$num_packages" -eq 0 ]; then
        log "WARN" "没有配置任何自定义包。"
        return 1
    fi

    echo -e "\n${BLUE}--- 选择要更新的自定义包 ---${NC}"
    local i=1
    # 使用 sort 命令让包名按字母排序显示
    local sorted_pkg_names=($(printf "%s\n" "${pkg_names[@]}" | sort))

    for pkg_name in "${sorted_pkg_names[@]}"; do
        echo -e " ${GREEN}$i.${NC} $pkg_name"
        ((i++))
    done
    echo -e " ${GREEN}0.${NC} 返回主菜单"
    echo -e "${BLUE}----------------------------${NC}"

    local choice_pkg
    read -rp "请输入包的序号 [0-$num_packages]: " choice_pkg

    # 验证选择
    if [[ ! "$choice_pkg" =~ ^[0-9]+$ ]]; then
        log "ERROR" "无效输入，请输入数字。"
        return 1
    fi

    if [ "$choice_pkg" -eq 0 ]; then
        log "INFO" "返回主菜单。"
        return 0 # 返回成功，表示正常退出选择
    elif [ "$choice_pkg" -ge 1 ] && [ "$choice_pkg" -le "$num_packages" ]; then
        local selected_pkg=${sorted_pkg_names[$((choice_pkg-1))]}
        log "INFO" "选择更新包: $selected_pkg"
        update_specific_package "$selected_pkg" # 调用更新函数
        return $? # 返回更新函数的执行结果
    else
        log "ERROR" "无效的选择序号: $choice_pkg"
        return 1
    fi
}

#---------------主函数---------------#
main() {
    # 0. 设置颜色变量
    setup_colors

    # 1. 初始化日志系统 (会进行第一次输出重定向)
    init_logger || exit 1 # 初始化失败则退出

    # 2. 检查运行环境和依赖
    log "INFO" "检查运行环境..."
    local dep_missing=false
    if [ ! -f "Makefile" ] || [ ! -d "scripts" ] || [ ! -d ".git" ]; then
        log "ERROR" "脚本必须在 OpenWrt 源码的根目录下运行 (需要存在 Makefile, scripts, .git)。"
        dep_missing=true
    fi
    for cmd in git make nproc tee cut dirname mkdir rm git date printf sort read; do
        if ! command -v "$cmd" &> /dev/null; then
            log "ERROR" "缺少必要的系统命令: $cmd"
            dep_missing=true
        fi
    done
     if [ "$dep_missing" = true ]; then
        log "ERROR" "环境或依赖检查失败，请修正后重试。"
        # 恢复原始输出，避免后续可能的错误信息无法显示
        exec >&$STDOUT_ORIG
        exec 2>&$STDERR_ORIG
        exit 1
    fi
    log "INFO" "环境检查通过。"

    # 记录脚本启动信息
    log "INFO" "${BOLD}OpenWrt 构建管理脚本已启动${NC}"
    log "INFO" "PID: $$"
    log "INFO" "会话日志目录: $SESSION_DIR"

    # 3. 主菜单循环
    local choice # 提前声明 choice
    while true; do
        print_menu # 显示菜单并获取输入到 choice 变量
        log "DEBUG" "用户选择了: $choice" # 记录用户选择

        # 根据选择执行操作
        case $choice in
            1) full_build ;;
            2) clean_workspace ;;
            3) update_all_components ;;
            4) clean_packages ;;
            5) build_firmware ;;
            6) menuconfig ;;
            7) update_custom_package ;;
            8) select_specific_package ;;
            9) update_source ;;
            10) update_feeds ;;
            0)
                log "INFO" "收到退出命令，正在退出脚本..."
                # 恢复原始输出流 (好习惯)
                exec >&$STDOUT_ORIG
                exec 2>&$STDERR_ORIG
                echo -e "${GREEN}脚本已退出。${NC}"
                exit 0
                ;;
            *)
                log "WARN" "无效的选项: '$choice'，请输入 0 到 10 之间的数字。"
                ;;
        esac

        local last_exit_code=$? # 获取上一个命令的退出状态码
        # 操作完成后暂停，给用户查看结果的时间
        if [[ $choice != 0 ]]; then
            if [ $last_exit_code -eq 0 ]; then
                echo -e "\n${GREEN}操作 '$choice' 执行完成。${NC}"
            else
                 echo -e "\n${RED}操作 '$choice' 执行时遇到错误 (退出码: $last_exit_code)。${NC}"
            fi
             echo -e "${YELLOW}按 Enter 键返回主菜单...${NC}"
             read -r # 等待用户按回车
        fi
    done
}

#---------------脚本入口---------------#
# 将所有主逻辑放入 main 函数，并在最后调用它
# "$@" 将所有命令行参数传递给 main 函数 (虽然本脚本目前未使用)
main "$@"
