#!/bin/bash

# APM软件包转换器 - 将DEB包转换为APM格式
log.warn()  { echo -e "[\e[33mWARN\e[0m]:  \e[1m$*\e[0m"; }
log.error() { echo -e "[\e[31mERROR\e[0m]: \e[1m$*\e[0m"; }
log.info()  { echo -e "[\e[96mINFO\e[0m]:  \e[1m$*\e[0m"; }
log.debug() { echo -e "[\e[32mDEBUG\e[0m]: \e[1m$*\e[0m"; }

SCRIPT_NAME=$(basename "$0")

if ! command -v dpkg > /dev/null ; then
    log.error "若想使用APM软件包转换器，您需先安装dpkg"
    exit 1
fi

# 显示用法信息
usage() {
    echo "用法: $SCRIPT_NAME [--manual] --base <basename> [basename ...] [--base <basename> ...] [--addons <addon-name> ...] <deb文件路径>"
    echo "       或者在手动模式下不传入 DEB 文件： $SCRIPT_NAME --manual --base <basename> [basename ...] [--base <basename> ...]"
    echo ""
    echo "参数说明:"
    echo "  --manual     启用手动模式：融合挂载后打开交互 shell，退出 shell 后脚本继续"
    echo "  --basename   必填参数（非手动模式下），指定基础环境名称，可一次指定多个或多次使用"
    echo "  --addons     可选参数，指定额外挂载的 addons 包名称，可多次使用"
    echo "  deb文件路径  要转换的DEB文件路径（非手动且非空模式下必填）"
    echo "  --pkgname    可选参数，指定新包的包名（默认使用原DEB包名）"
    echo "  --version    可选参数，指定新包的版本号（默认在原版本后追加'-apm'）"
    echo ""
    echo "示例:"
    echo "  $SCRIPT_NAME --base amber-pm-trixie /path/to/package.deb"
    echo "  $SCRIPT_NAME --base amber-pm-trixie amber-pm-trixie-gxde-base /path/to/package.deb"
    echo "  $SCRIPT_NAME --base amber-pm-trixie --addons amber-pm-trixie-nvidia-addons /path/to/package.deb"
    echo "  $SCRIPT_NAME --manual --base amber-pm-trixie   # 只融合挂载并进入手动 shell"
    echo "  $SCRIPT_NAME --manual --base amber-pm-trixie --pkgname newpkg --version 1.2.3 /path/to/package.deb"
    echo ""
    echo "说明: 最下层的base在最后面，从上到下写base"
}

# 解析参数
BASENAMES=()        # 存放实际用于构建 overlay 的 base（可能会被递归添加）
BASENAMES_ORIG=()   # 存放用户原始输入的 base 列表（用于 control 中 Depends 等）
ADDONS=()           # 存放用户显式指定的 addons 包名
SELECTED_ADDONS=()  # 存放本次转换要写入应用 info_layer_addons 的 addons
DEB_PATH=""
PKGNAME=""
VERSION=""
MANUAL_MODE=false

# 简单参数解析（顺序敏感）
while [ $# -gt 0 ]; do
    case "$1" in
        --base)
            shift
            if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
                log.error "--base 后需要跟名称"
                usage
                exit 1
            fi
            while [ $# -gt 0 ]; do
                [[ "$1" == -* ]] && break
                if [ -n "$DEB_PATH" ]; then
                    log.error "未知参数或多余的参数: $1"
                    usage
                    exit 1
                fi
                if [ -f "$1" ]; then
                    DEB_PATH="$1"
                    shift
                    break
                fi
                BASENAMES+=("$1")
                BASENAMES_ORIG+=("$1")
                shift
            done
            ;;
        --addons)
            if [ -z "$2" ]; then
                log.error "--addons 后需要跟 addons 包名"
                usage
                exit 1
            fi
            ADDONS+=("$2")
            SELECTED_ADDONS+=("$2")
            shift 2
            ;;
        --pkgname)
            PKGNAME="$2"
            shift 2
            ;;
        --version)
            VERSION="$2"
            shift 2
            ;;
        --manual)
            MANUAL_MODE=true
            shift
            ;;
        -*)
            log.error "未知选项: $1"
            usage
            exit 1
            ;;
        *)
            # 非选项，视为 DEB 路径（只接受第一个非选项作为 DEB）
            if [ -z "$DEB_PATH" ]; then
                DEB_PATH="$1"
                shift
            else
                log.error "未知参数或多余的参数: $1"
                usage
                exit 1
            fi
            ;;
    esac
done

# 基本参数验证：
# 如果不是手动模式，则至少需要一个 --base 和一个 deb 文件
if [ "$MANUAL_MODE" = false ]; then
    if [ ${#BASENAMES[@]} -eq 0 ] || [ -z "$DEB_PATH" ]; then
        log.error "错误：非手动模式下至少需要一个 --base 参数 且 必须提供 DEB 文件路径"
        usage
        exit 1
    fi
else
    # 手动模式下允许没有 DEB_FILE，但仍然要有至少一个 base
    if [ ${#BASENAMES[@]} -eq 0 ]; then
        log.error "错误：手动模式下仍需提供至少一个 --base 参数"
        usage
        exit 1
    fi
fi

# 如果传入了 DEB_PATH，检查文件是否存在
if [ -n "$DEB_PATH" ] && [ ! -f "$DEB_PATH" ]; then
    log.error "错误：DEB文件不存在: $DEB_PATH"
    exit 1
fi

log.info "开始转换（手动模式: $MANUAL_MODE）"
log.info "基础环境数量: ${#BASENAMES_ORIG[@]}"
for i in "${!BASENAMES_ORIG[@]}"; do
    log.info "  原始基础环境 $((i+1)): ${BASENAMES_ORIG[$i]}"
done

if [ -n "$DEB_PATH" ]; then
    log.info "目标 DEB: $DEB_PATH"
else
    log.info "未提供 DEB 文件，处于纯手动模式（手动修改/安装/打包）"
fi

# 1. 创建临时工作目录
CRAFT_DIR="$HOME/apm-craft-$$"
log.info "创建临时工作目录: $CRAFT_DIR"
mkdir -p "$CRAFT_DIR"/{core,work,mergedir,modified_deb,extract,new-pkg}
export CRAFT_DIR

# 检查是否已挂载，避免重复挂载
cleanup_mount() {
    if mountpoint -q "$CRAFT_DIR/mergedir"; then
        log.info "解除挂载: $CRAFT_DIR/mergedir"
        sudo umount "$CRAFT_DIR/mergedir" || true
    fi
}

# 清理函数
cleanup() {
    log.info "开始清理..."
    cleanup_mount
    if [ -d "$CRAFT_DIR" ]; then
        log.info "删除临时目录: $CRAFT_DIR"
        sudo rm -rf "$CRAFT_DIR"
    fi
}

# 设置退出时清理
trap cleanup EXIT

# 辅助函数：追加数组项并去重
_append_unique() {
    local array_name="$1"
    local item="$2"
    [ -z "$item" ] && return

    local existing
    eval 'for existing in "${'"$array_name"'[@]}"; do
        [ "$existing" = "$item" ] && return
    done'
    eval "$array_name"'+=("$item")'
}

_pkg_dir() {
    local pkgname="$1"
    local pkg_dir="/var/lib/apm/${pkgname}"
    if [ ! -d "$pkg_dir" ]; then
        pkg_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/${pkgname}"
    fi
    [ -d "$pkg_dir" ] && echo "$pkg_dir"
}

_is_addon_pkg() {
    local pkg_dir
    pkg_dir="$(_pkg_dir "$1")"
    [ -n "$pkg_dir" ] && [ -f "${pkg_dir}/info_addon_base" ]
}

# 递归获取info文件中的依赖 (会把新依赖追加到 BASENAMES 数组中)
get_recursive_basenames() {
    local basename="$1"
    # 注意：根据之前脚本结构，info 存放在 /var/lib/apm/apm/files/ace-env/var/lib/apm/<basename>/info
    local base_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/$basename"
    local info_file="$base_dir/info"

    if [ -f "$info_file" ]; then
        log.info "读取info文件: $info_file"
        while IFS= read -r base; do
            [[ -z "$base" ]] && continue
            # 如果依赖的 base 没有被记录过，则递归添加
            local found=false
            for existing in "${BASENAMES[@]}"; do
                if [ "$existing" = "$base" ]; then
                    found=true
                    break
                fi
            done
            if [ "$found" = false ]; then
                BASENAMES+=("$base")
                get_recursive_basenames "$base"
            fi
        done < "$info_file"
    else
        log.info "未找到info文件，跳过: $info_file"
    fi
}

BASE_INPUTS=("${BASENAMES[@]}")
BASENAMES=()

# 将 --base 中的 addons 转换为显式 addons，并把其 info 依赖的 base 加入 base 列表。
for BASE in "${BASE_INPUTS[@]}"; do
    if _is_addon_pkg "$BASE"; then
        log.info "检测到 --base 指向 addons: $BASE"
        _append_unique ADDONS "$BASE"
        _append_unique SELECTED_ADDONS "$BASE"

        addon_info="$(_pkg_dir "$BASE")/info"
        if [ -f "$addon_info" ]; then
            while IFS= read -r addon_base; do
                [ -z "$addon_base" ] && continue
                _append_unique BASENAMES "$addon_base"
            done < "$addon_info"
        else
            log.warn "addons 缺少 info，无法自动补 base 依赖: $BASE"
        fi
    else
        _append_unique BASENAMES "$BASE"
    fi
done

BASENAMES_ORIG=("${BASENAMES[@]}")

# 递归获取所有基础环境（从规范化后的 base 开始）
for BASE in "${BASENAMES[@]}"; do
    get_recursive_basenames "$BASE"
done

# 如果用户传了 DEB，则读取原包信息（否则跳过）
if [ -n "$DEB_PATH" ]; then
    log.info "检查原DEB包信息..."
    ORIG_PKGNAME=$(dpkg -f "$DEB_PATH" Package 2>/dev/null || echo "")
    ORIG_VERSION=$(dpkg -f "$DEB_PATH" Version 2>/dev/null || echo "")
    ORIG_ARCH=$(dpkg -f "$DEB_PATH" Architecture 2>/dev/null || echo "")

    log.info "原包名: ${ORIG_PKGNAME:-未知}"
    log.info "原版本: ${ORIG_VERSION:-未知}"
    log.info "原架构: ${ORIG_ARCH:-unknown}"
else
    ORIG_PKGNAME=""
    ORIG_VERSION=""
    ORIG_ARCH="$(dpkg --print-architecture 2>/dev/null || echo "unknown")"
fi

# 设置新包名和版本（若手动模式且未指定，则稍后询问）
NEW_PKGNAME="${PKGNAME:-${ORIG_PKGNAME}}"
NEW_VERSION="${VERSION:-${ORIG_VERSION}-apm}"

log.info "将使用的新包名: ${NEW_PKGNAME:-<未指定>}"
log.info "将使用的新版本: ${NEW_VERSION:-<未指定>}"
log.info "使用的架构: $ORIG_ARCH"

# 2. 构建 lowerdir 路径（多个 base 按顺序叠放，只包含本次显式选择的 addons）
log.info "构建 overlay lowerdir 路径..."
LOWERDIRS=()

for BASENAME in "${BASENAMES[@]}"; do
    ACE_ENV_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/ace-env"
    CORE_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${BASENAME}/files/core"

    if [ -d "$ACE_ENV_PATH" ]; then
        log.info "使用 ace-env 路径: $ACE_ENV_PATH"
        LOWERDIRS+=("$ACE_ENV_PATH")
    elif [ -d "$CORE_PATH" ]; then
        log.info "使用 core 路径: $CORE_PATH"
        LOWERDIRS+=("$CORE_PATH")
    else
        log.error "错误：基础环境路径不存在: $BASENAME"
        log.error "  检查的路径: $ACE_ENV_PATH"
        log.error "  检查的路径: $CORE_PATH"
        exit 1
    fi
done

# 追加本次显式选择的 addons（放在 bases 之上）
for addon in "${ADDONS[@]}"; do
    ADDON_PATH="/var/lib/apm/${addon}"
    if [ ! -d "$ADDON_PATH" ]; then
        ADDON_PATH="/var/lib/apm/apm/files/ace-env/var/lib/apm/${addon}"
    fi

    if [ -d "${ADDON_PATH}/files/ace-env" ]; then
        log.info "使用显式 addon ace-env 路径: ${ADDON_PATH}/files/ace-env"
        LOWERDIRS+=("${ADDON_PATH}/files/ace-env")
    elif [ -d "${ADDON_PATH}/files/core" ]; then
        log.info "使用显式 addon core 路径: ${ADDON_PATH}/files/core"
        LOWERDIRS+=("${ADDON_PATH}/files/core")
    else
        log.error "错误：显式指定的 addon 路径不存在: $addon"
        log.error "  检查的路径: ${ADDON_PATH}"
        exit 1
    fi
done

# 将 lowerdirs 数组用冒号连接
LOWERDIR=$(IFS=:; echo "${LOWERDIRS[*]}")
log.debug "最终 lowerdir: $LOWERDIR"

# 3. 进行融合挂载
log.info "正在进行融合挂载..."
sudo fuse-overlayfs \
    -o "lowerdir=$LOWERDIR,upperdir=$CRAFT_DIR/core/,workdir=$CRAFT_DIR/work/" \
    "$CRAFT_DIR/mergedir"

if ! mountpoint -q "$CRAFT_DIR/mergedir"; then
    log.error "错误：融合挂载失败"
    exit 1
fi

log.info "挂载完成: $CRAFT_DIR/mergedir"

# 导出 chrootEnvPath 以便 ace-run-pkg 使用（并在需要时传递给 sudo -E）
export chrootEnvPath="$CRAFT_DIR/mergedir"
log.debug "已导出 chrootEnvPath=$chrootEnvPath"

# 如果在手动模式下，立即打开交互 shell 并在退出后继续脚本
if [ "$MANUAL_MODE" = true ]; then
    log.info "进入手动模式：将在融合挂载环境中打开交互 shell（使用 ace-run-pkg）。"
    log.info "在 shell 中，您可以手动修改、测试安装或进行其他操作。退出 shell 后脚本将继续。"
    # 启动交互 shell，保留环境变量（使用 sudo -E）
    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || {
        log.warn "ace-run-pkg shell 退出或出现错误，继续脚本..."
    }
    log.info "用户已退出手动 shell，脚本将继续。"
    # 如果没有 DEB，询问是否要进行后续打包（允许返回 shell）
    if [ -z "$DEB_PATH" ]; then
        while true; do
            echo ""
            read -r -p "未提供 DEB 文件。是否现在进行新 APM 包的自动打包？ (y = 打包, r = 返回 shell, n = 跳过打包) [y/r/n]: " yn
            case "$yn" in
                y|Y)
                    # 如果缺少包名或版本，交互询问
                    if [ -z "$NEW_PKGNAME" ]; then
                        read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME
                    fi
                    if [ -z "$NEW_VERSION" ] || [[ "$NEW_VERSION" == "-apm" ]]; then
                        read -r -p "请输入要创建的版本 (Version): " NEW_VERSION
                    fi
                    break
                    ;;
                r|R)
                    log.info "返回交互 shell（使用 ace-run-pkg）。退出 shell 后再次询问。"
                    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg bash --login || true
                    ;;
                n|N)
                    log.info "跳过自动打包。脚本结束。"
                    exit 0
                    ;;
                *)
                    echo "请输入 y, r, 或 n。"
                    ;;
            esac
        done
    fi
fi

# 到这里：非手动模式或手动模式退出后继续（如果是非手动并且有 DEB，继续原本流程）

# 函数：查找并处理符号链接，返回实际文件路径
resolve_symlink() {
    local file="$1"
    local target_dir="$2"
    
    if [ -L "$file" ]; then
        # 获取符号链接目标
        local target=$(readlink "$file")
        
        # 如果目标是绝对路径，则在目标目录中查找
        if [[ "$target" == /* ]]; then
            local resolved_path="$target_dir${target}"
            if [ -f "$resolved_path" ]; then
                echo "$resolved_path"
                return 0
            fi
        else
            # 相对路径，在符号链接所在目录解析
            local link_dir=$(dirname "$file")
            local resolved_path="$link_dir/$target"
            if [ -f "$resolved_path" ]; then
                echo "$resolved_path"
                return 0
            fi
        fi
    fi
    
    # 如果不是符号链接或解析失败，返回原文件
    echo "$file"
}

# 函数：交互式选择文件复制到entries目录（用于手动模式无DEB情况）
# 函数：交互式选择文件复制到entries目录（用于手动模式无DEB情况）
interactive_copy_entries() {
    local core_dir="$CRAFT_DIR/core"
    local entries_dir="$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries"
    
    log.info "开始交互式选择文件复制到 entries 目录..."
    mkdir -p "$entries_dir/applications" "$entries_dir/icons"
    
    # 查找桌面文件（保留完整路径）
    local desktop_files=()
    while IFS= read -r -d '' file; do
        [[ -f "$file" ]] && desktop_files+=("$file")
    done < <(find "$core_dir/usr/share" -name "*.desktop" -print0 2>/dev/null || true)
    
    # 查找图标文件（保留完整路径）
    local icon_files=()
    while IFS= read -r -d '' file; do
        [[ -f "$file" ]] && icon_files+=("$file")
    done < <(find "$core_dir/usr/share" \( -name "*.png" -o -name "*.svg" -o -name "*.xpm" \) -print0 2>/dev/null || true)
    
    # 处理桌面文件
    if [ ${#desktop_files[@]} -gt 0 ]; then
        log.info "找到 ${#desktop_files[@]} 个桌面文件:"
        for i in "${!desktop_files[@]}"; do
            local file="${desktop_files[$i]}"
            # 显示完整路径（相对于 core_dir）
            local relative_path="${file#$core_dir}"
            echo "  $((i+1)). $relative_path"
            
            # 检查是否是符号链接
            if [ -L "$file" ]; then
                local target=$(readlink "$file")
                echo "      → 符号链接指向: $target"
                # 解析符号链接获取实际文件
                local resolved_file=$(resolve_symlink "$file" "$core_dir")
                if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then
                    local resolved_relative="${resolved_file#$core_dir}"
                    echo "      → 解析为: $resolved_relative"
                    desktop_files[$i]="$resolved_file"
                fi
            fi
        done
        
        echo ""
        read -r -p "请选择要复制的桌面文件编号（多个用逗号分隔，all=全部，none=跳过）: " desktop_choice
        
        if [[ "$desktop_choice" =~ ^[Aa][Ll][Ll]$ ]]; then
            # 复制所有桌面文件到 entries/applications，但保持目录结构
            for file in "${desktop_files[@]}"; do
                local relative_path="${file#$core_dir}"
                local dest_filename=$(basename "$file")
                
                # 如果文件在 applications 目录下，直接复制到 entries/applications
                if [[ "$relative_path" == /usr/share/applications/* ]]; then
                    local dest_path="$entries_dir/applications/$dest_filename"
                else
                    # 其他位置的桌面文件，保持相对路径结构
                    local path_dir=$(dirname "$relative_path")
                    local dest_dir="$entries_dir/applications$path_dir"
                    mkdir -p "$dest_dir"
                    local dest_path="$dest_dir/$dest_filename"
                fi
                
                cp -v "$file" "$dest_path"
                
                # 处理桌面文件内容
                process_desktop_file "$dest_path" "$NEW_PKGNAME"
            done
        elif [[ ! "$desktop_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$desktop_choice" ]; then
            # 处理选择的文件
            IFS=',' read -ra choices <<< "$desktop_choice"
            for choice in "${choices[@]}"; do
                choice=$(echo "$choice" | tr -d ' ')
                if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#desktop_files[@]} ]; then
                    local idx=$((choice-1))
                    local file="${desktop_files[$idx]}"
                    local relative_path="${file#$core_dir}"
                    local dest_filename=$(basename "$file")
                    
                    # 根据路径决定目标位置
                    if [[ "$relative_path" == /usr/share/applications/* ]]; then
                        local dest_path="$entries_dir/applications/$dest_filename"
                    else
                        local path_dir=$(dirname "$relative_path")
                        local dest_dir="$entries_dir/applications$path_dir"
                        mkdir -p "$dest_dir"
                        local dest_path="$dest_dir/$dest_filename"
                    fi
                    
                    cp -v "$file" "$dest_path"
                    
                    # 处理桌面文件内容
                    process_desktop_file "$dest_path" "$NEW_PKGNAME"
                else
                    log.warn "无效的选择: $choice"
                fi
            done
        else
            log.info "跳过桌面文件复制"
        fi
    else
        log.info "未找到桌面文件"
    fi
    
    # 处理图标文件
    if [ ${#icon_files[@]} -gt 0 ]; then
        log.info "找到 ${#icon_files[@]} 个图标文件:"
        for i in "${!icon_files[@]}"; do
            local file="${icon_files[$i]}"
            local relative_path="${file#$core_dir}"
            echo "  $((i+1)). $relative_path"
            
            # 检查是否是符号链接
            if [ -L "$file" ]; then
                local target=$(readlink "$file")
                echo "      → 符号链接指向: $target"
                # 解析符号链接获取实际文件
                local resolved_file=$(resolve_symlink "$file" "$core_dir")
                if [ "$resolved_file" != "$file" ] && [ -f "$resolved_file" ]; then
                    local resolved_relative="${resolved_file#$core_dir}"
                    echo "      → 解析为: $resolved_relative"
                    icon_files[$i]="$resolved_file"
                fi
            fi
        done
        
        echo ""
        read -r -p "请选择要复制的图标文件编号（多个用逗号分隔，all=全部，none=跳过）: " icon_choice
        
        if [[ "$icon_choice" =~ ^[Aa][Ll][Ll]$ ]]; then
            # 复制所有图标文件到 entries/icons，保持目录结构
            for file in "${icon_files[@]}"; do
                local relative_path="${file#$core_dir}"
                local dest_filename=$(basename "$file")
                
                # 如果文件在 icons 主题目录下，直接复制到 entries/icons
                if [[ "$relative_path" == /usr/share/icons/* ]] || 
                   [[ "$relative_path" == /usr/share/pixmaps/* ]]; then
                    local dest_path="$entries_dir/icons/$dest_filename"
                else
                    # 其他位置的图标文件，保持相对路径结构
                    local path_dir=$(dirname "$relative_path")
                    local dest_dir="$entries_dir/icons$path_dir"
                    mkdir -p "$dest_dir"
                    local dest_path="$dest_dir/$dest_filename"
                fi
                
                cp -v "$file" "$dest_path"
            done
        elif [[ ! "$icon_choice" =~ ^[Nn][Oo][Nn][Ee]$ ]] && [ -n "$icon_choice" ]; then
            # 处理选择的文件
            IFS=',' read -ra choices <<< "$icon_choice"
            for choice in "${choices[@]}"; do
                choice=$(echo "$choice" | tr -d ' ')
                if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#icon_files[@]} ]; then
                    local idx=$((choice-1))
                    local file="${icon_files[$idx]}"
                    local relative_path="${file#$core_dir}"
                    local dest_filename=$(basename "$file")
                    
                    # 根据路径决定目标位置
                    if [[ "$relative_path" == /usr/share/icons/* ]] || 
                       [[ "$relative_path" == /usr/share/pixmaps/* ]]; then
                        local dest_path="$entries_dir/icons/$dest_filename"
                    else
                        local path_dir=$(dirname "$relative_path")
                        local dest_dir="$entries_dir/icons$path_dir"
                        mkdir -p "$dest_dir"
                        local dest_path="$dest_dir/$dest_filename"
                    fi
                    
                    cp -v "$file" "$dest_path"
                else
                    log.warn "无效的选择: $choice"
                fi
            done
        else
            log.info "跳过图标文件复制"
        fi
    else
        log.info "未找到图标文件"
    fi
}



# 函数：处理桌面文件内容
# 函数：处理桌面文件内容（安全版本，避免重复处理）
process_desktop_file() {
    local desktop_file="$1"
    local pkgname="$2"
    # 新增：精确路径检查
    local apps_path1="/usr/share/applications"
    local apps_path2="/opt/apps/${ORIG_PKGNAME}/entries/applications"
    local apps_path3="/usr/local/share/applications"
    
    if [[ ! "$desktop_file" =~ ^.*${apps_path1}/.*\.desktop$ ]] && 
       [[ ! "$desktop_file" =~ ^.*${apps_path2}/.*\.desktop$ ]] &&
       [[ ! "$desktop_file" =~ ^.*${apps_path3}/.*\.desktop$ ]]; then
        log.debug "跳过非应用程序 desktop 文件: $desktop_file"
        return 0
    fi
    
    log.info "处理桌面文件: $desktop_file"
    
    # 检查文件是否已经处理过（避免重复添加 apm run）
    if grep -q "^Exec=apm run $pkgname " "$desktop_file"; then
        log.info "桌面文件已经处理过，跳过: $desktop_file"
        return 0
    fi
    
    # 检查是否有其他包的 apm run 前缀（清理旧的）
    if grep -q "^Exec=apm run [^ ]* " "$desktop_file"; then
        log.info "发现旧的 apm run 前缀，清理后重新添加"
        # 移除所有 apm run 前缀
        sed -i "s|^Exec=apm run [^ ]* ||" "$desktop_file"
    fi
    
    # 尝试用 busybox dos2unix（若不存在则跳过转换）
    if command -v busybox >/dev/null 2>&1; then
        busybox dos2unix "$desktop_file" 2>/dev/null || true
    else
        dos2unix "$desktop_file" 2>/dev/null || true
    fi
    
    # 处理 Exec 行：在原有命令前追加 apm run $pkgname
    if grep -q '^Exec=' "$desktop_file"; then
        sed -i "s|^Exec=\(.*\)$|Exec=apm run $pkgname \1|" "$desktop_file"
    fi
    
    # 删除 TryExec 行
    if grep -q '^TryExec=' "$desktop_file"; then
        sed -i '/^TryExec=/d' "$desktop_file"
        log.info "已删除 TryExec 行"
    fi
    
    # 处理 Icon 路径（若以 / 开头）
    if grep -q '^Icon=/' "$desktop_file"; then
        sed -i "s|^Icon=/|Icon=/var/lib/apm/apm/files/ace-env/var/lib/apm/$pkgname/files/core/|" "$desktop_file"
    fi
    
    # 添加 X-APM-APPID（如果不存在）
    if ! grep -q "X-APM-APPID" "$desktop_file"; then
        echo "" >> "$desktop_file"
        echo "X-APM-APPID=$pkgname" >> "$desktop_file"
    fi
    
    # 检查修改结果并打印调试
    if grep -q "apm run $pkgname" "$desktop_file"; then
        log.info "桌面文件修改成功: $desktop_file"
    else
        log.warn "桌面文件可能未正确修改: $desktop_file"
    fi
}


# 4. 如果有 DEB 文件，进行自动化的检查、解包与修改
if [ -n "$DEB_PATH" ]; then

    # 在融合环境中更新包列表并做 dry-run 检查（如果 ace-run-pkg aptss 可用）
    log.info "在融合环境中测试安装 DEB 包（dry-run）..."
    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss update || log.warn "aptss update 返回非零状态，继续但请注意"
    if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss install "$DEB_PATH" --dry-run ; then
        log.error "错误：安装前检查失败，DEB包可能无法在基础环境中安装"
        log.error "请检查依赖关系或基础环境是否兼容"
        exit 1
    fi
    log.info "安装前检查通过，准备进行提取与修改..."
    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg mkdir -p /var/cache/apt/archives/partial

    # 提取 DEB 包内容并准备修改
    log.info "提取并修改原DEB包..."
    EXTRACT_DIR="$CRAFT_DIR/extract"
    MODIFIED_DEB_DIR="$CRAFT_DIR/modified_deb"
    mkdir -p "$EXTRACT_DIR"
    mkdir -p "$MODIFIED_DEB_DIR/DEBIAN"

    dpkg -x "$DEB_PATH" "$EXTRACT_DIR"
    dpkg -e "$DEB_PATH" "$MODIFIED_DEB_DIR/DEBIAN"

    # 处理 .desktop 文件
    DESKTOP_MODIFIED=false
    while IFS= read -r desktop_file; do
        [ -z "$desktop_file" ] && continue
        process_desktop_file "$desktop_file" "${NEW_PKGNAME:-$ORIG_PKGNAME}"
        DESKTOP_MODIFIED=true
    done < <(find "$EXTRACT_DIR" -name "*.desktop" -print)

    if [ "$DESKTOP_MODIFIED" = false ]; then
        log.info "未找到需要修改的 .desktop 文件"
    fi

    # 复制修改后的文件结构到打包目录并重新打包 modified deb（供本地测试/安装使用）
    MODIFIED_DEB_PATH="$CRAFT_DIR/modified_${ORIG_PKGNAME:-package}.deb"
    log.info "重新打包修改后的 DEB: $MODIFIED_DEB_PATH"
    mkdir -p "$MODIFIED_DEB_DIR/data"
    cp -r "$EXTRACT_DIR"/* "$MODIFIED_DEB_DIR/" 2>/dev/null || true

    (cd "$MODIFIED_DEB_DIR" && fakeroot dpkg-deb --build -Z none . "$MODIFIED_DEB_PATH") || {
        log.error "错误：重新打包 DEB 失败"
        exit 1
    }

    if [ ! -f "$MODIFIED_DEB_PATH" ]; then
        log.error "错误：重新打包后的 DEB 未生成: $MODIFIED_DEB_PATH"
        exit 1
    fi
    log.info "修改后的 DEB 包已生成: $MODIFIED_DEB_PATH"

    # 可选：在融合环境中实际安装修改后的包（默认使用 ssaudit 命令）
    if ! sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg ssaudit "$MODIFIED_DEB_PATH" --native --no-create-desktop-entry ; then
        log.error "错误：修改后的 DEB 包安装失败（ssaudit）"
        exit 1
    fi
    log.info "修改后的 DEB 包安装完成（ssaudit）"


fi

    # 清理 apt 缓存
    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg aptss clean || true
    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/apt/lists || true
    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/lib/aptss/lists || true
    sudo -E chrootEnvPath="$chrootEnvPath" /var/lib/apm/apm/files/ace-run-pkg rm -vfr /var/cache/apt/archives/* || true

#清理 .dpkg-new 文件
log.info "搜索并清理 .dpkg-new 文件..."
# 在 core 目录下查找并删除所有以 .dpkg-new 结尾的文件
# 删除 .dpkg-new 文件（去掉后缀）
log.info "删除 .dpkg-new 文件.."
find "$CRAFT_DIR/core" -name "*.dpkg-new"  2>/dev/null | while read -r file; do

    sudo rm -vfr "$file" 
done

# 统计清理结果
COUNT=$(find "$CRAFT_DIR/core" -name "*.dpkg-new" -type f 2>/dev/null | wc -l)
if [ "$COUNT" -eq 0 ]; then
    log.info "已清理所有 .dpkg-new 文件"
else
    log.warn "仍有 $COUNT 个 .dpkg-new 文件存在"
fi


# 5. 创建新的 APM 包结构
log.info "创建新的APM包结构..."
PKG_BUILD_DIR="$CRAFT_DIR/new-pkg"
mkdir -p "$PKG_BUILD_DIR/DEBIAN"
mkdir -p "$PKG_BUILD_DIR/var/lib/apm/$NEW_PKGNAME"/{entries,files} 2>/dev/null || true

# info 和 info_debug：写入原始输入的 base 列表 和 递归展开后的 base 列表
log.info "创建 info 文件（包含原始输入的基础环境）..."
: > "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info" 2>/dev/null || true
for BASENAME in "${BASENAMES_ORIG[@]}"; do
    echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info"
    log.info "  写入: $BASENAME"
done

log.info "创建 info_debug 文件（包含所有递归依赖的基础环境）..."
: > "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_debug" 2>/dev/null || true
for BASENAME in "${BASENAMES[@]}"; do
    echo "$BASENAME" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_debug"
    log.info "  写入: $BASENAME"
done

if [ ${#SELECTED_ADDONS[@]} -gt 0 ]; then
    log.info "创建 info_layer_addons 文件（仅包含本次选择的 addons）..."
    : > "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_layer_addons" 2>/dev/null || true
    for addon in "${SELECTED_ADDONS[@]}"; do
        echo "$addon" >> "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/info_layer_addons"
        log.info "  写入 addon: $addon"
    done
fi

# 创建 postrm 脚本
cat > "$PKG_BUILD_DIR/DEBIAN/postrm" << 'EOF'
#!/bin/bash
PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE"

if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then
    echo "清理卸载残留"
    rm -rf "/var/lib/apm/$PACKAGE_NAME"
    for username in $(ls /home); do
        if [ -d "/home/$username/.apm/$PACKAGE_NAME" ]; then
            rm -fr "/home/$username/.apm/$PACKAGE_NAME"
        fi
    done
else
    echo "非卸载，跳过清理"
fi
EOF

chmod +x "$PKG_BUILD_DIR/DEBIAN/postrm"

# 6. 复制需要的文件到新的 APM 包
log.info "复制文件到新的APM包..."

# 如果是手动模式且没有DEB文件，进行交互式文件选择
if [ "$MANUAL_MODE" = true ] && [ -z "$DEB_PATH" ]; then
    interactive_copy_entries
fi

# 复制 /usr/share 内容到 entries
if [ -d "$CRAFT_DIR/extract/usr/share" ]; then
    log.info "复制 /usr/share 内容..."
    mkdir -p "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries"
    cp -r "$CRAFT_DIR/extract/usr/share/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true
fi

# 复制 /opt/apps/<orig_pkg>/entries（如果存在）
if [ -n "$ORIG_PKGNAME" ] && [ -d "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries" ]; then
    log.info "复制 /opt/apps/$ORIG_PKGNAME/entries 内容..."
    cp -r "$CRAFT_DIR/extract/opt/apps/$ORIG_PKGNAME/entries/"* "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/entries/" 2>/dev/null || true
fi

# 复制融合环境（core, work）到新的包内 files（以便运行时使用）
log.info "复制融合环境文件..."
sudo cp -r "$CRAFT_DIR"/core "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/files/" 2>/dev/null || true
sudo cp -r "$CRAFT_DIR"/work "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/files/" 2>/dev/null || true

# 设置文件权限
sudo chmod -R 755 "$PKG_BUILD_DIR/var/lib/apm/${NEW_PKGNAME}/files/" 2>/dev/null || true

# 7. 解除挂载（如果尚未解除）
log.info "解除挂载..."
cleanup_mount

# 8. 计算目录大小函数
calculate_directory_size() {
    local dir="$1"
    if [ -d "$dir" ]; then
        du -sk "$dir" | cut -f1
    else
        echo "0"
    fi
}

# 构建依赖字符串 - 包含规范化后的 base 和显式指定的 addons（用于 control）
DEPENDS_PARTS=("${BASENAMES_ORIG[@]}")

# 如果包名是 addons 格式（*-addons），确保 base 已在依赖中
if [[ "${NEW_PKGNAME}" == *-addons ]]; then
    log.info "检测到 addons 包，确保 base 依赖已包含"
fi

# 追加显式指定的 addons 到依赖
for addon in "${ADDONS[@]}"; do
    FOUND_ADDON=false
    for existing in "${DEPENDS_PARTS[@]}"; do
        if [ "$existing" = "$addon" ]; then
            FOUND_ADDON=true
            break
        fi
    done
    if [ "$FOUND_ADDON" = false ]; then
        DEPENDS_PARTS+=("$addon")
    fi
done

DEPENDS_STR=$(IFS=,; echo "${DEPENDS_PARTS[*]}")

# 若打包前没有 NEW_PKGNAME/NEW_VERSION，交互询问（一般出现在手动无DEB场景）
if [ -z "$NEW_PKGNAME" ]; then
    read -r -p "请输入要创建的包名 (Package): " NEW_PKGNAME
fi
if [ -z "$NEW_VERSION" ] || [[ "$NEW_VERSION" == "-apm" ]]; then
    read -r -p "请输入要创建的版本 (Version): " NEW_VERSION
fi

# 创建 control 文件
cat > "${PKG_BUILD_DIR}/DEBIAN/control" << EOF
Package: $NEW_PKGNAME
Version: $NEW_VERSION
Architecture: $ORIG_ARCH
Maintainer: APM Converter <shenmo@spark-app.store>
Depends: $DEPENDS_STR
Installed-Size: $(calculate_directory_size "$PKG_BUILD_DIR")
Description: APM converted package from ${ORIG_PKGNAME:-original}
  This package was automatically converted from the original deb package.
  Based on: ${BASENAMES_ORIG[*]}
EOF

# 9. 打包并生成输出文件名
OUTPUT_DEB="${NEW_PKGNAME}_${NEW_VERSION}_${ORIG_ARCH}.deb"
log.info "开始使用 fakeroot 打包: $OUTPUT_DEB"
fakeroot dpkg-deb -Z xz --build "$PKG_BUILD_DIR" "$OUTPUT_DEB" || {
    log.error "错误：打包 APM 包失败"
    exit 1
}

log.info "转换完成！"
log.info "生成的APM包: $OUTPUT_DEB"
log.info "包名: $NEW_PKGNAME"
log.info "版本: $NEW_VERSION"
log.info "架构: $ORIG_ARCH"
log.info "依赖: $DEPENDS_STR"
log.info "基础环境（原始输入）: ${BASENAMES_ORIG[*]}"
log.info "基础环境（递归展开）: ${BASENAMES[*]}"
log.info "注意：桌面文件如存在已被修改，添加了 apm run 前缀和 X-APM-APPID"

# 退出（trap 会触发 cleanup）
exit 0
