#!/bin/bash

#######################################
# Zip文件合并脚本 - CentOS 7.9 / RHEL 8.0
# 
# 功能：
# 1. 识别 XuguDB-12.0.0 文件（基础文件）
# 2. 按OS和CPU架构分组合并其他文件
# 3. 没有OS/CPU架构的文件追加到所有基础文件
# 4. 支持排除指定文件不进行合并
#######################################

set -e

# 排除列表 - 指定要排除的zip文件名称（支持正则表达式）
# 例如: EXCLUDE_PATTERNS=("genchecksum" "test-*" "*-demo.zip")
EXCLUDE_PATTERNS=("XuguDB-Migrator*")

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

# 初始化临时目录
# 确保TMPDIR设置正确，如果为空则使用默认值
if [ -z "$TMPDIR" ] || [ ! -d "$TMPDIR" ] || [ ! -w "$TMPDIR" ]; then
    if [ -w "/tmp" ]; then
        export TMPDIR="/tmp"
    elif [ -w "/var/tmp" ]; then
        export TMPDIR="/var/tmp"
    elif [ -w "$HOME" ]; then
        export TMPDIR="$HOME/.tmp"
        mkdir -p "$TMPDIR"
    else
        export TMPDIR="."
    fi
fi

# 日志函数
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[OK]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

log_debug() {
    # 调试日志，可以通过设置VERBOSE=true启用
    if [ "${VERBOSE:-false}" = "true" ]; then
        echo -e "${CYAN}[DEBUG]${NC} $1"
    fi
}

# 检查文件是否在排除列表中
should_exclude_file() {
    local filename=$1
    
    # 如果没有排除模式，返回0（不排除）
    if [ ${#EXCLUDE_PATTERNS[@]} -eq 0 ]; then
        return 1
    fi
    
    # 检查文件名是否匹配排除模式
    for pattern in "${EXCLUDE_PATTERNS[@]}"; do
        if [[ "$filename" =~ $pattern ]]; then
            return 0  # 匹配到排除模式，返回0（排除）
        fi
    done
    
    return 1  # 未匹配排除模式，返回1（不排除）
}

# 检查依赖
check_dependencies() {
    log_info "检查依赖工具..."
    
    local missing_tools=()
    
    # 检查必要工具
    for tool in unzip zip; do
        if ! command -v $tool &> /dev/null; then
            missing_tools+=("$tool")
        fi
    done
    
    if [ ${#missing_tools[@]} -gt 0 ]; then
        log_error "缺少必要工具: ${missing_tools[*]}"
        log_info "在CentOS/RHEL上，请运行: sudo yum install -y unzip zip"
        exit 1
    fi
    
    log_success "依赖检查完成"
}

# 支持的操作系统和CPU架构
# 国产OS说明：kylin(麒麟), deepin(深度), uos(统信UOS) 都是Linux发行版
SUPPORTED_OS=("windows" "linux" "macos" "kylin" "deepin" "uos")

# 国产CPU架构说明：
#   loongarch64 - 龙芯LoongArch 64位
#   phytium - 飞腾ARM处理器
#   zhaoxin - 兆芯x86处理器
#   kunpeng - 鲲鹏ARM处理器(华为)
SUPPORTED_ARCH=("amd64" "aarch64" "x86_64" "arm64" "loongarch64" "phytium" "zhaoxin" "kunpeng")

# 获取唯一的临时目录名
get_unique_tempdir() {
    local base=$1
    local counter=1
    while [ -d "${base}_${counter}" ]; do
        ((counter++))
    done
    echo "${base}_${counter}"
}

# 提取操作系统信息
extract_os() {
    local filename=$1
    for os in "${SUPPORTED_OS[@]}"; do
        if [[ $filename =~ $os ]]; then
            echo "$os"
            return
        fi
    done
    echo ""
}

# 提取架构信息
extract_architecture() {
    local filename=$1
    for arch in "${SUPPORTED_ARCH[@]}"; do
        if [[ $filename =~ $arch ]]; then
            echo "$arch"
            return
        fi
    done
    echo ""
}

# 检查两个架构是否等价
# x86_64 和 amd64 在Windows上等价
# arm64 和 aarch64 在ARM平台上等价
arch_equivalent() {
    local arch1=$1
    local arch2=$2
    
    # 完全相同则等价
    if [ "$arch1" = "$arch2" ]; then
        return 0
    fi
    
    # x86_64 和 amd64 等价
    if [ "$arch1" = "x86_64" ] && [ "$arch2" = "amd64" ]; then
        return 0
    fi
    if [ "$arch1" = "amd64" ] && [ "$arch2" = "x86_64" ]; then
        return 0
    fi
    
    # arm64 和 aarch64 等价
    if [ "$arch1" = "arm64" ] && [ "$arch2" = "aarch64" ]; then
        return 0
    fi
    if [ "$arch1" = "aarch64" ] && [ "$arch2" = "arm64" ]; then
        return 0
    fi
    
    return 1
}

# 生成校验码
generate_checksums() {
    local zip_file=$1
    
    if [ ! -f "$zip_file" ]; then
        log_error "文件不存在: $zip_file"
        return 1
    fi
    
    # 移除.zip后缀，添加-checksums.txt后缀
    local checksum_file="${zip_file%.zip}-checksums.txt"
    
    log_info "生成校验码文件: $checksum_file"
    
    # 清空或创建新文件，首先写入文件名
    echo "$zip_file" > "$checksum_file"
    
    # 生成各种校验码
    if command -v md5sum &> /dev/null; then
        local sum=$(md5sum "$zip_file" | cut -d' ' -f1)
        echo "MD5: $sum" >> "$checksum_file"
        log_debug "  MD5: $sum"
    fi
    
    if command -v sha1sum &> /dev/null; then
        local sum=$(sha1sum "$zip_file" | cut -d' ' -f1)
        echo "SHA1: $sum" >> "$checksum_file"
        log_debug "  SHA1: $sum"
    fi
    
    if command -v sha256sum &> /dev/null; then
        local sum=$(sha256sum "$zip_file" | cut -d' ' -f1)
        echo "SHA256: $sum" >> "$checksum_file"
        log_debug "  SHA256: $sum"
    fi
    
    if command -v sha512sum &> /dev/null; then
        local sum=$(sha512sum "$zip_file" | cut -d' ' -f1)
        echo "SHA512: $sum" >> "$checksum_file"
        log_debug "  SHA512: $sum"
    fi
    
    log_success "校验码文件生成完成"
    return 0
}

# 主函数
main() {
    local work_dir="${1:-.}"
    
    # 验证目录存在
    if [ ! -d "$work_dir" ]; then
        log_error "目录不存在: $work_dir"
        exit 1
    fi
    
    cd "$work_dir"
    log_info "工作目录: $(pwd)"
    
    # 检查是否存在zip文件
    if ! ls *.zip > /dev/null 2>&1; then
        log_error "未找到任何zip文件"
        exit 1
    fi
    
    # 初始化变量
    declare -A base_files
    declare -A base_files_os
    declare -A base_files_arch
    local -a other_files=()
    
    # 第一步：分类zip文件
    log_info "扫描zip文件..."
    
    for zip_file in *.zip; do
        # 检查是否在排除列表中
        if should_exclude_file "$zip_file"; then
            log_warn "  跳过排除文件: $zip_file"
            continue
        fi
        
        if [[ $zip_file == XuguDB-12.0.0* ]]; then
            local os=$(extract_os "$zip_file")
            local arch=$(extract_architecture "$zip_file")
            
            if [ -n "$os" ] && [ -n "$arch" ]; then
                base_files["$zip_file"]="$zip_file"
                # 存储OS和架构信息
                base_files_os["$zip_file"]="$os"
                base_files_arch["$zip_file"]="$arch"
                log_info "  基础文件: $zip_file -> OS: $os, Arch: $arch"
            fi
        else
            other_files+=("$zip_file")
        fi
    done
    
    if [ ${#base_files[@]} -eq 0 ]; then
        log_error "未找到 XuguDB-12.0.0 基础文件"
        exit 1
    fi
    
    log_success "找到 ${#base_files[@]} 个基础文件"
    log_info "待合并文件数: ${#other_files[@]}"
    
    # 第二步：为每个基础文件构建合并队列
    declare -A merge_queue
    
    log_info "分析待合并文件..."
    
    for base_zip in "${!base_files[@]}"; do
        local base_os="${base_files_os[$base_zip]}"
        local base_arch="${base_files_arch[$base_zip]}"
        merge_queue["$base_zip"]=""
        
        for source_zip in "${other_files[@]}"; do
            local source_os=$(extract_os "$source_zip")
            local source_arch=$(extract_architecture "$source_zip")
            
            # 决定是否合并此文件到基础文件
            local should_merge=false
            
            if [ -n "$source_os" ] && [ -n "$source_arch" ]; then
                # 源文件有OS和架构，两者都必须匹配（支持架构等价性）
                if [ "$source_os" = "$base_os" ] && arch_equivalent "$source_arch" "$base_arch"; then
                    should_merge=true
                    log_info "  $source_zip -> $base_zip (OS: $source_os, Arch: $source_arch 匹配)"
                fi
            elif [ -n "$source_os" ] || [ -n "$source_arch" ]; then
                # 源文件只有一个属性，至少匹配它拥有的属性
                if [ -n "$source_os" ] && [ "$source_os" = "$base_os" ]; then
                    should_merge=true
                    log_info "  $source_zip -> $base_zip (OS: $source_os 匹配)"
                elif [ -n "$source_arch" ] && arch_equivalent "$source_arch" "$base_arch"; then
                    should_merge=true
                    log_info "  $source_zip -> $base_zip (Arch: $source_arch 匹配)"
                fi
            else
                # 源文件既没有OS也没有架构，合并到所有基础文件
                should_merge=true
                log_info "  $source_zip -> $base_zip (无平台信息，合并到所有文件)"
            fi
            
            if [ "$should_merge" = true ]; then
                merge_queue["$base_zip"]+="$source_zip "
            fi
        done
    done
    
    # 第三步：执行合并
    log_info ""
    log_info "开始合并文件..."
    
    for base_zip in "${!base_files[@]}"; do
        local target_zip="${base_files[$base_zip]}"
        local files_to_merge=(${merge_queue[$base_zip]})
        
        if [ ${#files_to_merge[@]} -eq 0 ]; then
            local base_os="${base_files_os[$base_zip]}"
            local base_arch="${base_files_arch[$base_zip]}"
            log_warn "  $base_os-$base_arch: 没有待合并文件"
            continue
        fi
        
        log_info ""
        log_info "处理基础文件: $target_zip (${#files_to_merge[@]} 个文件)"
        
        local temp_dir=$(get_unique_tempdir "$TMPDIR/.zip_merge")
        mkdir -p "$temp_dir"
        
        # 解压基础文件
        local target_dir="$temp_dir/target"
        mkdir -p "$target_dir"
        
        log_info "  解压基础文件..."
        if ! unzip -q "$target_zip" -d "$target_dir"; then
            log_error "    解压失败: $target_zip"
            rm -rf "$temp_dir"
            continue
        fi
        
        # 合并源文件
        for source_zip in "${files_to_merge[@]}"; do
            log_info "  合并: $source_zip"
            
            local source_dir="$temp_dir/source_$$_$RANDOM"
            mkdir -p "$source_dir"
            
            if ! unzip -q "$source_zip" -d "$source_dir"; then
                log_warn "    解压失败，跳过"
                rm -rf "$source_dir"
                continue
            fi
            
            # 复制文件到目标目录
            cp -rf "$source_dir"/* "$target_dir/" 2>/dev/null || true
            rm -rf "$source_dir"
            
            log_success "    OK"
        done
        
        # 重新创建zip文件
        log_info "  重新创建zip文件..."
        local temp_zip="$temp_dir/temp.zip"
        
        if ! (cd "$target_dir" && zip -q -r "$temp_zip" .); then
            log_error "    创建zip失败"
            rm -rf "$temp_dir"
            continue
        fi
        
        # 替换原文件
        mv "$temp_zip" "$target_zip"
        log_success "  更新成功"
        
        # 清理临时目录
        rm -rf "$temp_dir"
    done
    
    # 显示未合并的文件
    log_info ""
    log_debug "DEBUG: merge_queue 内容:"
    for base_zip in "${!base_files[@]}"; do
        log_debug "  $base_zip -> ${merge_queue[$base_zip]}"
    done
    log_info "未合并的文件: (检查 ${#other_files[@]} 个文件)"
    local unmerged_count=0
    for source_zip in "${other_files[@]}"; do
        local source_os=$(extract_os "$source_zip")
        local source_arch=$(extract_architecture "$source_zip")
        local was_merged=false
        
        for base_zip in "${!base_files[@]}"; do
            # 检查这个文件是否被合并到任何基础文件
            if [ "$was_merged" = true ]; then
                break
            fi
            if [ -n "${merge_queue[$base_zip]}" ]; then
                local zips_to_merge=(${merge_queue[$base_zip]})
                for merged_file in "${zips_to_merge[@]}"; do
                    if [ "$merged_file" = "$source_zip" ]; then
                        was_merged=true
                        log_debug "  DEBUG: $source_zip 在 $base_zip 中找到"
                        break
                    fi
                done
            fi
        done
        
        if [ "$was_merged" = false ]; then
            if [ -n "$source_os" ] || [ -n "$source_arch" ]; then
                log_warn "  $source_zip (OS: $source_os, Arch: $source_arch) - 未找到匹配的基础文件"
            else
                log_warn "  $source_zip (无平台信息) - 未被合并"
            fi
            unmerged_count=$((unmerged_count + 1))
        fi
    done
    
    if [ $unmerged_count -eq 0 ]; then
        log_success "所有文件都已合并"
    else
        log_warn "共有 $unmerged_count 个文件未被合并"
    fi
    
    # 显示最终结果
    log_info ""
    log_success "合并完成!"
    log_info "最终文件:"
    
    for base_zip in "${!base_files[@]}"; do
        local file="${base_files[$base_zip]}"
        if [ -f "$file" ]; then
            local size=$(du -h "$file" | cut -f1)
            log_info "  $file"
            log_info "    大小: $size"
            
            # 生成校验码
            log_info "  生成校验码..."
            if generate_checksums "$file"; then
                log_success "    校验码已生成"
            else
                log_warn "    校验码生成失败"
            fi
        fi
    done
}

# 显示使用说明
show_usage() {
    cat << EOF
使用方法:
  $0 [目录]

参数:
  目录        zip文件所在的目录，默认为当前目录

例子:
  $0                  # 合并当前目录的zip文件
  $0 /path/to/files   # 合并指定目录的zip文件

系统要求:
  - CentOS 7.9 或 RHEL 8.0
  - unzip 和 zip 工具
  - bash 4.0+

EOF
}

# 处理命令行参数
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    show_usage
    exit 0
fi

# 检查依赖
check_dependencies

# 执行主函数
main "$@"
