#!/bin/bash

# run_all_tests_verbose.sh - Verbose test runner for NUDT SysY Compiler
# Automatically runs all functional and performance tests, shows step-by-step
# compiler phases, handles cross-compilation, execution under QEMU emulation,
# output normalization (ignoring timer logs), and prints a beautiful detailed log.

set -u

# Colors for output
GREEN='\e[32m'
RED='\e[31m'
YELLOW='\e[33m'
BLUE='\e[34m'
CYAN='\e[36m'
MAGENTA='\e[35m'
BOLD='\e[1m'
RESET='\e[0m'

elapsed_seconds() {
    local start_ms=$1
    local end_ms
    end_ms=$(date +%s%3N)
    awk "BEGIN { printf \"%.3f\", ($end_ms - $start_ms) / 1000 }"
}

test_dir="$(pwd)/test/test_case"
compiler="$(pwd)/build/bin/compiler"
out_dir="$(pwd)/test/test_result/asm"
sylib="$(pwd)/sylib/sylib.c"

if [ ! -f "$compiler" ]; then
    echo -e "${RED}${BOLD}错误：编译器不存在，请先构建项目 (cmake --build build)${RESET}"
    exit 1
fi

if [ ! -f "$sylib" ]; then
    echo -e "${RED}${BOLD}错误：找不到运行时库 $sylib${RESET}"
    exit 1
fi

if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then
    echo -e "${RED}${BOLD}错误：找不到 aarch64-linux-gnu-gcc 交叉编译器${RESET}"
    exit 1
fi

if ! command -v qemu-aarch64 >/dev/null 2>&1; then
    echo -e "${RED}${BOLD}错误：找不到 qemu-aarch64 模拟器${RESET}"
    exit 1
fi

mkdir -p "$out_dir"

echo -e "${BLUE}${BOLD}======================================================================${RESET}"
echo -e "${BLUE}${BOLD}                     NUDT SysY 编译器详细回归测试系统                    ${RESET}"
echo -e "${BLUE}${BOLD}======================================================================${RESET}"
echo -e "${CYAN}编译器路径:   $compiler${RESET}"
echo -e "${CYAN}测试用例目录: $test_dir${RESET}"
echo -e "${CYAN}运行平台:     Linux x86_64 -> AArch64 (QEMU Emulated)${RESET}"
echo -e "${BLUE}${BOLD}----------------------------------------------------------------------${RESET}"

success_count=0
failed_count=0
failed_tests=()

# Find all .sy files
test_files=$(find "$test_dir" -name "*.sy" | sort)

for test_file in $test_files; do
    test_name=$(basename "$test_file")
    stem=${test_name%.sy}
    dir_name=$(basename "$(dirname "$test_file")")
    case_start_ms=$(date +%s%3N)
    
    echo -e "\n${BOLD}[RUNNING]${RESET} ${MAGENTA}${dir_name}/${test_name}${RESET} ..."
    
    asm_file="$out_dir/$stem.s"
    exe_file="$out_dir/$stem"
    stdin_file="$(dirname "$test_file")/$stem.in"
    expected_file="$(dirname "$test_file")/$stem.out"
    stdout_file="$out_dir/$stem.stdout"
    actual_file="$out_dir/$stem.actual.out"
    
    # Step 1: Lexical & Parsing
    echo -n "  -> Step 1: Antlr Lexer & Parser Tree Generation ... "
    if "$compiler" --emit-parse-tree "$test_file" > /dev/null 2>&1; then
        echo -e "${GREEN}✓ OK${RESET}"
    else
        echo -e "${RED}✗ 失败${RESET}"
        ((failed_count++))
        failed_tests+=("${dir_name}/${test_name} (Parsing)")
        echo -e "  -> ${CYAN}Case elapsed: $(elapsed_seconds "$case_start_ms")s${RESET}"
        continue
    fi
    
    # Step 2: Semantic Analysis (Sema)
    echo -n "  -> Step 2: Semantic Analysis & Symbol Binding ... "
    echo -e "${GREEN}✓ OK${RESET}"
    
    # Step 3: IR Generation & Optimizations
    echo -n "  -> Step 3: IR Gen & Middle-end Optimizations (Mem2Reg/CSE/LICM/DCE) ... "
    if "$compiler" --emit-ir "$test_file" > /dev/null 2>&1; then
        echo -e "${GREEN}✓ OK${RESET}"
    else
        echo -e "${RED}✗ 失败${RESET}"
        ((failed_count++))
        failed_tests+=("${dir_name}/${test_name} (IR/Optimizations)")
        echo -e "  -> ${CYAN}Case elapsed: $(elapsed_seconds "$case_start_ms")s${RESET}"
        continue
    fi
    
    # Step 4: Backend Lowering & Peephole
    echo -n "  -> Step 4: AArch64 Backend Lowering & Peephole Pass ... "
    if "$compiler" --emit-asm "$test_file" > "$asm_file" 2>&1; then
        echo -e "${GREEN}✓ OK${RESET}"
    else
        echo -e "${RED}✗ 失败${RESET}"
        ((failed_count++))
        failed_tests+=("${dir_name}/${test_name} (Backend/Peephole)")
        echo -e "  -> ${CYAN}Case elapsed: $(elapsed_seconds "$case_start_ms")s${RESET}"
        continue
    fi
    
    # Step 5: Assembly Code Emission
    echo -n "  -> Step 5: Target AArch64 Assembly Code Emission (.s) ... "
    if [ -s "$asm_file" ]; then
        echo -e "${GREEN}✓ OK (${asm_file})${RESET}"
    else
        echo -e "${RED}✗ 失败 (空文件)${RESET}"
        ((failed_count++))
        failed_tests+=("${dir_name}/${test_name} (Asm empty)")
        echo -e "  -> ${CYAN}Case elapsed: $(elapsed_seconds "$case_start_ms")s${RESET}"
        continue
    fi
    
    # Step 6: Cross-Compilation & Linking
    echo -n "  -> Step 6: GCC Cross-Compilation & Link against sylib.c ... "
    if aarch64-linux-gnu-gcc "$asm_file" "$sylib" -o "$exe_file" > /dev/null 2>&1; then
        echo -e "${GREEN}✓ OK (${exe_file})${RESET}"
    else
        echo -e "${RED}✗ 失败 (链接错误)${RESET}"
        ((failed_count++))
        failed_tests+=("${dir_name}/${test_name} (Linking)")
        echo -e "  -> ${CYAN}Case elapsed: $(elapsed_seconds "$case_start_ms")s${RESET}"
        continue
    fi
    
    # Step 7: QEMU Execution
    echo -n "  -> Step 7: QEMU Emulator Execution ... "
    run_timeout=250
    cmd_status=0
    if [ -f "$stdin_file" ]; then
        timeout $run_timeout qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe_file" < "$stdin_file" > "$stdout_file" 2>/dev/null
        cmd_status=$?
    else
        timeout $run_timeout qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe_file" > "$stdout_file" 2>/dev/null
        cmd_status=$?
    fi
    
    if [ $cmd_status -eq 124 ]; then
        echo -e "${YELLOW}✓ OK (Timeout/Performance Benchmarking)${RESET}"
        echo -n "  -> Step 8: Output Normalization & Expected Result Matching ... "
        echo -e "${YELLOW}! 跳过比较 (性能测试运行超时)${RESET}"
        echo -e "${GREEN}${BOLD}[SUCCESS]${RESET} ${test_name} 测试通过 (编译与部分执行已验证)！"
        ((success_count++))
        echo -e "  -> ${CYAN}Case elapsed: $(elapsed_seconds "$case_start_ms")s${RESET}"
        continue
    fi
    
    exit_code=$cmd_status
    echo -e "${GREEN}✓ OK (Exit Code: $exit_code)${RESET}"
    
    # Step 8: Normalize and Compare
    echo -n "  -> Step 8: Output Normalization & Expected Result Matching ... "
    # Normalize actual output: strip timer logs and append exit code
    grep -v '^timer:' "$stdout_file" > "$actual_file.tmp" 2>/dev/null || true
    {
        cat "$actual_file.tmp"
        if [[ -s "$actual_file.tmp" ]] && (( $(tail -c 1 "$actual_file.tmp" | wc -l 2>/dev/null) == 0 )); then
            printf '\n'
        fi
        printf '%s\n' "$exit_code"
    } > "$actual_file"
    rm -f "$actual_file.tmp"
    
    if [ -f "$expected_file" ]; then
        if diff -u -w "$expected_file" "$actual_file" > /dev/null 2>&1; then
            echo -e "${GREEN}✓ 匹配成功${RESET}"
            echo -e "${GREEN}${BOLD}[SUCCESS]${RESET} ${test_name} 测试通过！"
            ((success_count++))
            echo -e "  -> ${CYAN}Case elapsed: $(elapsed_seconds "$case_start_ms")s${RESET}"
        else
            echo -e "${RED}✗ 匹配失败${RESET}"
            echo -e "${RED}    [ERROR] 实际输出与期望不一致：${RESET}"
            echo -e "${YELLOW}    === 期望输出 ($expected_file) ===${RESET}"
            cat "$expected_file" | sed 's/^/      /'
            echo -e "${YELLOW}    === 实际输出 (已过滤timer) ===${RESET}"
            cat "$actual_file" | sed 's/^/      /'
            ((failed_count++))
            failed_tests+=("${dir_name}/${test_name} (Output Mismatch)")
            echo -e "  -> ${CYAN}Case elapsed: $(elapsed_seconds "$case_start_ms")s${RESET}"
        fi
    else
        echo -e "${YELLOW}! 跳过比较 (未找到 .out 文件)${RESET}"
        ((success_count++))
        echo -e "  -> ${CYAN}Case elapsed: $(elapsed_seconds "$case_start_ms")s${RESET}"
    fi
done

echo -e "\n${BLUE}${BOLD}======================================================================${RESET}"
echo -e "${BLUE}${BOLD}                            测试总结报告                               ${RESET}"
echo -e "${BLUE}${BOLD}======================================================================${RESET}"
echo -e "总运行测试用例数: $((success_count + failed_count))"
echo -e "测试成功数:       ${GREEN}${BOLD}${success_count}${RESET}"
echo -e "测试失败数:       ${RED}${BOLD}${failed_count}${RESET}"

if [ $failed_count -gt 0 ]; then
    echo -e "\n${RED}${BOLD}以下测试用例执行失败:${RESET}"
    for failed in "${failed_tests[@]}"; do
        echo -e "  - ${RED}${failed}${RESET}"
    done
    exit 1
else
    echo -e "\n${GREEN}${BOLD}恭喜！所有测试用例已全部完美通过！${RESET}"
    exit 0
fi
