#!/bin/bash
set -e

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

# 基础配置（与手动测试参数同步）
TEST_FILE="./.fio_test.tmp"
JSON_FILE="./.fio_json.tmp"
TEST_SIZE="1G"                  # 与手动测试保持一致
RUNTIME=60                      # 与手动测试保持一致
IO_ENGINE="libaio"              # 与手动测试保持一致
IO_DEPTH=16                     # 与手动测试保持一致
NUM_JOBS=1                      # 与手动测试保持一致
RESULTS=()
DEBUG_LOG="./.fio_debug.log"

# 初始化日志
> "$DEBUG_LOG"
rm -f "$TEST_FILE" "$JSON_FILE"

# 调试日志函数
debug() {
    echo "[$(date +'%H:%M:%S')] $1" >> "$DEBUG_LOG"
}

# 检查命令是否存在
command_exists() {
    command -v "$1" &> /dev/null
}

# 安装依赖
install_dependencies() {
    echo -e "${YELLOW}正在安装必要测试工具...${NC}"
    if command_exists apt; then
        sudo apt update -qq > /dev/null || { echo -e "${RED}更新软件源失败${NC}"; exit 1; }
        sudo apt install -y -qq fio jq bc > /dev/null || { echo -e "${RED}安装fio/jq/bc失败${NC}"; exit 1; }
    elif command_exists dnf; then
        sudo dnf install -y -q fio jq bc > /dev/null || { echo -e "${RED}安装fio/jq/bc失败${NC}"; exit 1; }
    elif command_exists yum; then
        sudo yum install -y -q fio jq bc > /dev/null || { echo -e "${RED}安装fio/jq/bc失败${NC}"; exit 1; }
    elif command_exists brew; then
        brew install -q fio jq bc > /dev/null || { echo -e "${RED}安装fio/jq/bc失败${NC}"; exit 1; }
    else
        echo -e "${RED}无法识别的包管理器${NC}"; exit 1;
    fi
}

# 检查测试环境
check_environment() {
    echo -e "${BLUE}====================================${NC}"
    echo -e "${BLUE}          环境检查                  ${NC}"
    echo -e "${BLUE}====================================${NC}"
    debug "开始环境检查"
    
    # 空间检查（考虑测试文件大小和系统预留）
    local size_num=$(echo "$TEST_SIZE" | grep -oP '^\d+')
    local size_unit=$(echo "$TEST_SIZE" | grep -oP '[A-Za-z]+$')
    local required_space="$((size_num * 2))${size_unit}"  # 预留双倍空间
    echo -e "• 需要至少${CYAN}${required_space}${NC}可用空间..."
    
    # 转换为字节进行比较
    if ! test_size_bytes=$(numfmt --from=iec "$required_space" 2>/dev/null); then
        echo -e "${RED}空间单位解析错误，请检查TEST_SIZE配置${NC}"; exit 1;
    fi
    
    # 获取当前目录可用空间（字节）
    if ! avail_space=$(df -P --block-size=1 . 2>/dev/null | awk 'NR==2 {print $4}'); then
        echo -e "${RED}获取可用空间失败${NC}"; exit 1;
    fi
    
    if [ "$avail_space" -lt "$test_size_bytes" ]; then
        avail_human=$(numfmt --to=iec "$avail_space")
        req_human=$(numfmt --to=iec "$test_size_bytes")
        echo -e "${RED}可用空间不足，需要${req_human}，实际可用${avail_human}${NC}"; exit 1;
    fi
    
    # 权限检查
    if [ ! -w "$(dirname "$TEST_FILE")" ]; then
        echo -e "${RED}测试目录无写入权限${NC}"; exit 1;
    fi
    
    # 依赖检查
    if ! (command_exists fio && command_exists jq && command_exists bc); then
        install_dependencies
    else
        echo -e "• ${GREEN}所有依赖已安装${NC}"
    fi
    
    # 验证fio与libaio兼容性
    echo -e "• 验证fio功能及libaio引擎..."
    fio --name=verify --rw=read --size=1M --runtime=2 \
        --filename="$TEST_FILE" --output-format=json --output="$JSON_FILE" \
        --ioengine="$IO_ENGINE" --iodepth="$IO_DEPTH" --direct=1 > /dev/null 2>&1
    if [ ! -s "$JSON_FILE" ] || [ "$(jq -r '.jobs[0].read.iops' "$JSON_FILE")" = "null" ]; then
        echo -e "${RED}fio或libaio引擎验证失败${NC}"; exit 1;
    fi
    
    rm -f "$TEST_FILE" "$JSON_FILE"
    echo -e "• ${GREEN}环境检查通过${NC}\n"
}

# 格式化单位显示
format_iops() {
    local iops=$1
    if (( $(echo "$iops >= 1000000" | bc -l) )); then
        echo "$iops" | awk '{printf "%.2fM", $1/1000000}'
    elif (( $(echo "$iops >= 1000" | bc -l) )); then
        echo "$iops" | awk '{printf "%.2fK", $1/1000}'
    else
        echo "$iops" | awk '{printf "%.2f", $1}'
    fi
}

# 执行测试（同步手动测试参数）
run_test() {
    local test_name=$1
    local rw_mode=$2
    local bs=$3
    local data_type="read"
    [[ $rw_mode == *"write"* ]] && data_type="write"
    
    echo -e "${YELLOW}------------------------------------${NC}"
    echo -e "${YELLOW}        执行${test_name}测试         ${NC}"
    echo -e "${YELLOW}------------------------------------${NC}"
    echo -e "• 模式: ${CYAN}${rw_mode}${NC}"
    echo -e "• 块大小: ${CYAN}${bs}${NC}"
    echo -e "• IO引擎: ${CYAN}${IO_ENGINE}${NC}"
    echo -e "• IO队列深度: ${CYAN}${IO_DEPTH}${NC}"
    echo -e "• 直接IO: ${CYAN}启用${NC}"
    debug "开始${test_name}测试: $rw_mode, $bs"
    
    # 执行fio测试（完整同步手动参数）
    fio --name="${test_name}" \
        --rw="${rw_mode}" \
        --bs="${bs}" \
        --size="${TEST_SIZE}" \
        --runtime="${RUNTIME}" \
        --filename="${TEST_FILE}" \
        --output-format=json \
        --output="${JSON_FILE}" \
        --group_reporting \
        --ioengine="${IO_ENGINE}" \
        --iodepth="${IO_DEPTH}" \
        --direct=1 \
        --numjobs="${NUM_JOBS}"
    
    # 提取数据
    local iops=$(jq -r ".jobs[0].${data_type}.iops" "$JSON_FILE")
    local bw_kb=$(jq -r ".jobs[0].${data_type}.bw" "$JSON_FILE")
    
    # 显示原始提取结果
    echo -e "\n${PURPLE}原始性能数据:${NC}"
    echo -e "• IOPS: ${CYAN}${iops}${NC}"
    echo -e "• 带宽: ${CYAN}${bw_kb} KB/s${NC}"
    
    # 处理异常值
    if [ "$iops" = "null" ] || [ -z "$iops" ]; then iops=0; fi
    if [ "$bw_kb" = "null" ] || [ -z "$bw_kb" ]; then bw_kb=0; fi
    
    # 转换单位
    local bw_mb=$(echo "scale=2; $bw_kb / 1024" | bc)
    local iops_display=$(format_iops "$iops")
    
    # 保存结果
    RESULTS+=("${test_name}|${iops_display}|${bw_mb}")
    debug "${test_name}结果: IOPS=${iops}, 带宽=${bw_kb}KB/s"
    
    # 清理
    rm -f "$TEST_FILE" "$JSON_FILE"
    echo -e "\n${GREEN}${test_name}测试完成${NC}\n"
}

# 主函数
main() {
    echo -e "${BLUE}====================================${NC}"
    echo -e "${BLUE}        硬盘性能测试工具            ${NC}"
    echo -e "${BLUE}====================================${NC}\n"
    start_time=$(date +%s)
    
    # 环境检查
    check_environment
    
    # 执行测试（保持与手动测试相同的块大小）
    run_test "随机读取" "randread" "4k"
    run_test "随机写入" "randwrite" "4k"
    run_test "顺序读取" "read" "128k"
    run_test "顺序写入" "write" "128k"
    
    # 汇总结果
    end_time=$(date +%s)
    total_time=$((end_time - start_time))
    
    echo -e "${BLUE}====================================${NC}"
    echo -e "${BLUE}          测试汇总结果              ${NC}"
    echo -e "${BLUE}====================================${NC}"
    echo -e "总耗时: ${YELLOW}$((total_time/60))分$((total_time%60))秒${NC}\n"
    
    # 美化表格输出
    printf "%-12s | %-10s | %-16s\n" "测试类型" "IOPS" "吞吐量(MB/s)"
    echo "--------------------------------------------------------"
    for res in "${RESULTS[@]}"; do
        IFS='|' read -r name iops bw <<< "$res"
        printf "%-12s | %-10s | %-16.2f\n" "$name" "$iops" "$bw"
    done
    echo "--------------------------------------------------------"
    
    echo -e "\n${GREEN}所有测试完成${NC}"
    echo -e "调试日志: ${DEBUG_LOG}"
}

# 启动测试
main
