#!/bin/bash

# QAUP 集成测试脚本

set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
TEST_LOG="$PROJECT_ROOT/logs/integration_test_$(date +%Y%m%d_%H%M%S).log"

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

print_message() {
    local color=$1
    local message=$2
    echo -e "${color}${message}${NC}"
    echo "$(date '+%Y-%m-%d %H:%M:%S') $message" >> "$TEST_LOG"
}

# 测试结果统计
TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0
FAILED_TEST_NAMES=()

# 记录测试结果
record_test_result() {
    local test_name=$1
    local result=$2
    
    TOTAL_TESTS=$((TOTAL_TESTS + 1))
    
    if [ "$result" = "PASS" ]; then
        PASSED_TESTS=$((PASSED_TESTS + 1))
        print_message $GREEN "✓ $test_name: PASS"
    else
        FAILED_TESTS=$((FAILED_TESTS + 1))
        FAILED_TEST_NAMES+=("$test_name")
        print_message $RED "✗ $test_name: FAIL"
    fi
}

# 等待服务就绪
wait_for_service() {
    local service_name=$1
    local url=$2
    local max_attempts=${3:-30}
    local attempt=0
    
    print_message $BLUE "等待 $service_name 服务就绪..."
    
    while [ $attempt -lt $max_attempts ]; do
        if curl -f -s "$url" &>/dev/null; then
            print_message $GREEN "$service_name 服务已就绪"
            return 0
        fi
        
        sleep 2
        attempt=$((attempt + 1))
        
        if [ $((attempt % 10)) -eq 0 ]; then
            print_message $YELLOW "$service_name 等待中... ($attempt/$max_attempts)"
        fi
    done
    
    print_message $RED "$service_name 服务启动超时"
    return 1
}

# 测试 Docker 环境
test_docker_environment() {
    print_message $BLUE "测试 Docker 环境..."
    
    # 测试 Docker 是否运行
    if docker info &>/dev/null; then
        record_test_result "Docker服务运行" "PASS"
    else
        record_test_result "Docker服务运行" "FAIL"
        return 1
    fi
    
    # 测试 Docker Compose 是否可用
    if docker-compose --version &>/dev/null; then
        record_test_result "Docker Compose可用" "PASS"
    else
        record_test_result "Docker Compose可用" "FAIL"
        return 1
    fi
    
    # 测试网络连接
    if docker network ls | grep -q qaup; then
        record_test_result "Docker网络存在" "PASS"
    else
        record_test_result "Docker网络存在" "FAIL"
    fi
    
    return 0
}

# 测试容器启动
test_container_startup() {
    print_message $BLUE "测试容器启动..."
    
    local containers=("qaup-postgres" "qaup-redis" "qaup-app" "qaup-nginx")
    
    for container in "${containers[@]}"; do
        if docker ps --format "{{.Names}}" | grep -q "^${container}$"; then
            record_test_result "${container}容器运行" "PASS"
        else
            record_test_result "${container}容器运行" "FAIL"
        fi
    done
}

# 测试服务健康检查
test_service_health() {
    print_message $BLUE "测试服务健康检查..."
    
    # 测试数据库健康检查
    if docker exec qaup-postgres pg_isready -h localhost -p 5432 -U postgres &>/dev/null; then
        record_test_result "PostgreSQL健康检查" "PASS"
    else
        record_test_result "PostgreSQL健康检查" "FAIL"
    fi
    
    # 测试 Redis 健康检查
    if docker exec qaup-redis redis-cli ping | grep -q "PONG"; then
        record_test_result "Redis健康检查" "PASS"
    else
        record_test_result "Redis健康检查" "FAIL"
    fi
    
    # 测试应用健康检查
    if wait_for_service "QAUP应用" "http://localhost:8080/actuator/health" 30; then
        record_test_result "应用健康检查" "PASS"
    else
        record_test_result "应用健康检查" "FAIL"
    fi
    
    # 测试 Nginx 健康检查
    if wait_for_service "Nginx" "http://localhost/health" 10; then
        record_test_result "Nginx健康检查" "PASS"
    else
        record_test_result "Nginx健康检查" "FAIL"
    fi
}

# 测试网络连通性
test_network_connectivity() {
    print_message $BLUE "测试网络连通性..."
    
    # 测试应用到数据库的连接
    if docker exec qaup-app nc -z qaup-postgres 5432 &>/dev/null; then
        record_test_result "应用到数据库连接" "PASS"
    else
        record_test_result "应用到数据库连接" "FAIL"
    fi
    
    # 测试应用到 Redis 的连接
    if docker exec qaup-app nc -z qaup-redis 6379 &>/dev/null; then
        record_test_result "应用到Redis连接" "PASS"
    else
        record_test_result "应用到Redis连接" "FAIL"
    fi
    
    # 测试 Nginx 到应用的连接
    if docker exec qaup-nginx nc -z qaup-app 8080 &>/dev/null; then
        record_test_result "Nginx到应用连接" "PASS"
    else
        record_test_result "Nginx到应用连接" "FAIL"
    fi
}

# 测试数据库功能
test_database_functionality() {
    print_message $BLUE "测试数据库功能..."
    
    # 测试数据库连接
    if docker exec qaup-postgres psql -U postgres -d qaup -c "SELECT 1;" &>/dev/null; then
        record_test_result "数据库连接测试" "PASS"
    else
        record_test_result "数据库连接测试" "FAIL"
        return 1
    fi
    
    # 测试 PostGIS 扩展
    if docker exec qaup-postgres psql -U postgres -d qaup -c "SELECT PostGIS_Version();" &>/dev/null; then
        record_test_result "PostGIS扩展测试" "PASS"
    else
        record_test_result "PostGIS扩展测试" "FAIL"
    fi
    
    # 测试表结构
    local table_count=$(docker exec qaup-postgres psql -U postgres -d qaup -t -c "SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public';" | xargs)
    if [ "$table_count" -gt 0 ]; then
        record_test_result "数据库表结构测试" "PASS"
        print_message $BLUE "数据库包含 $table_count 个表"
    else
        record_test_result "数据库表结构测试" "FAIL"
    fi
    
    # 测试数据库写入
    local test_table="integration_test_$(date +%s)"
    if docker exec qaup-postgres psql -U postgres -d qaup -c "CREATE TABLE $test_table (id SERIAL PRIMARY KEY, test_data TEXT); INSERT INTO $test_table (test_data) VALUES ('test'); DROP TABLE $test_table;" &>/dev/null; then
        record_test_result "数据库写入测试" "PASS"
    else
        record_test_result "数据库写入测试" "FAIL"
    fi
}

# 测试 Redis 功能
test_redis_functionality() {
    print_message $BLUE "测试 Redis 功能..."
    
    # 测试 Redis 基本操作
    if docker exec qaup-redis redis-cli set test_key "test_value" | grep -q "OK"; then
        record_test_result "Redis写入测试" "PASS"
    else
        record_test_result "Redis写入测试" "FAIL"
        return 1
    fi
    
    # 测试 Redis 读取
    if docker exec qaup-redis redis-cli get test_key | grep -q "test_value"; then
        record_test_result "Redis读取测试" "PASS"
    else
        record_test_result "Redis读取测试" "FAIL"
    fi
    
    # 清理测试数据
    docker exec qaup-redis redis-cli del test_key &>/dev/null
    
    # 测试 Redis 内存使用
    local memory_usage=$(docker exec qaup-redis redis-cli info memory | grep "used_memory_human" | cut -d: -f2 | tr -d '\r')
    if [ -n "$memory_usage" ]; then
        record_test_result "Redis内存信息测试" "PASS"
        print_message $BLUE "Redis 内存使用: $memory_usage"
    else
        record_test_result "Redis内存信息测试" "FAIL"
    fi
}

# 测试应用 API
test_application_api() {
    print_message $BLUE "测试应用 API..."
    
    # 测试健康检查端点
    local health_response=$(curl -s http://localhost:8080/actuator/health)
    if echo "$health_response" | grep -q '"status":"UP"'; then
        record_test_result "应用健康端点测试" "PASS"
    else
        record_test_result "应用健康端点测试" "FAIL"
    fi
    
    # 测试应用信息端点
    if curl -f -s http://localhost:8080/actuator/info &>/dev/null; then
        record_test_result "应用信息端点测试" "PASS"
    else
        record_test_result "应用信息端点测试" "FAIL"
    fi
    
    # 测试应用指标端点
    if curl -f -s http://localhost:8080/actuator/metrics &>/dev/null; then
        record_test_result "应用指标端点测试" "PASS"
    else
        record_test_result "应用指标端点测试" "FAIL"
    fi
    
    # 测试应用响应时间
    local response_time=$(curl -o /dev/null -s -w '%{time_total}' http://localhost:8080/actuator/health)
    if (( $(echo "$response_time < 5.0" | bc -l) )); then
        record_test_result "应用响应时间测试" "PASS"
        print_message $BLUE "应用响应时间: ${response_time}s"
    else
        record_test_result "应用响应时间测试" "FAIL"
        print_message $YELLOW "应用响应时间较慢: ${response_time}s"
    fi
}

# 测试前端访问
test_frontend_access() {
    print_message $BLUE "测试前端访问..."
    
    # 测试 Nginx 健康检查
    if curl -f -s http://localhost/health | grep -q "healthy"; then
        record_test_result "前端健康检查测试" "PASS"
    else
        record_test_result "前端健康检查测试" "FAIL"
    fi
    
    # 测试前端页面访问
    local http_status=$(curl -o /dev/null -s -w '%{http_code}' http://localhost/)
    if [ "$http_status" = "200" ]; then
        record_test_result "前端页面访问测试" "PASS"
    else
        record_test_result "前端页面访问测试" "FAIL"
        print_message $YELLOW "HTTP状态码: $http_status"
    fi
    
    # 测试 API 代理
    local api_status=$(curl -o /dev/null -s -w '%{http_code}' http://localhost/prod-api/actuator/health)
    if [ "$api_status" = "200" ]; then
        record_test_result "API代理测试" "PASS"
    else
        record_test_result "API代理测试" "FAIL"
        print_message $YELLOW "API代理状态码: $api_status"
    fi
    
    # 测试静态资源
    if curl -f -s http://localhost/favicon.ico &>/dev/null; then
        record_test_result "静态资源访问测试" "PASS"
    else
        record_test_result "静态资源访问测试" "FAIL"
    fi
}

# 测试数据持久化
test_data_persistence() {
    print_message $BLUE "测试数据持久化..."
    
    # 测试数据库数据持久化
    local test_data="persistence_test_$(date +%s)"
    
    # 创建测试数据
    if docker exec qaup-postgres psql -U postgres -d qaup -c "CREATE TABLE IF NOT EXISTS test_persistence (id SERIAL PRIMARY KEY, data TEXT); INSERT INTO test_persistence (data) VALUES ('$test_data');" &>/dev/null; then
        record_test_result "数据库数据创建测试" "PASS"
    else
        record_test_result "数据库数据创建测试" "FAIL"
        return 1
    fi
    
    # 重启数据库容器
    print_message $BLUE "重启数据库容器测试持久化..."
    docker restart qaup-postgres &>/dev/null
    
    # 等待数据库重新启动
    sleep 10
    
    # 验证数据是否仍然存在
    if docker exec qaup-postgres psql -U postgres -d qaup -t -c "SELECT data FROM test_persistence WHERE data = '$test_data';" | grep -q "$test_data"; then
        record_test_result "数据库持久化测试" "PASS"
    else
        record_test_result "数据库持久化测试" "FAIL"
    fi
    
    # 清理测试数据
    docker exec qaup-postgres psql -U postgres -d qaup -c "DELETE FROM test_persistence WHERE data = '$test_data';" &>/dev/null
    
    # 测试 Redis 持久化
    docker exec qaup-redis redis-cli set persistence_test "$test_data" &>/dev/null
    docker restart qaup-redis &>/dev/null
    sleep 5
    
    if docker exec qaup-redis redis-cli get persistence_test | grep -q "$test_data"; then
        record_test_result "Redis持久化测试" "PASS"
    else
        record_test_result "Redis持久化测试" "FAIL"
    fi
    
    # 清理 Redis 测试数据
    docker exec qaup-redis redis-cli del persistence_test &>/dev/null
}

# 测试文件上传功能
test_file_upload() {
    print_message $BLUE "测试文件上传功能..."
    
    # 创建测试文件
    local test_file="/tmp/test_upload_$(date +%s).txt"
    echo "This is a test file for upload functionality" > "$test_file"
    
    # 检查上传目录是否存在
    if [ -d "$PROJECT_ROOT/data/uploads" ]; then
        # 模拟文件上传（复制到上传目录）
        cp "$test_file" "$PROJECT_ROOT/data/uploads/"
        
        if [ -f "$PROJECT_ROOT/data/uploads/$(basename "$test_file")" ]; then
            record_test_result "文件上传测试" "PASS"
            
            # 清理测试文件
            rm -f "$PROJECT_ROOT/data/uploads/$(basename "$test_file")"
        else
            record_test_result "文件上传测试" "FAIL"
        fi
    else
        record_test_result "文件上传目录检查" "FAIL"
    fi
    
    # 清理临时文件
    rm -f "$test_file"
}

# 测试日志功能
test_logging() {
    print_message $BLUE "测试日志功能..."
    
    # 检查应用日志
    if docker logs qaup-app --tail 10 | grep -q "Started"; then
        record_test_result "应用日志测试" "PASS"
    else
        record_test_result "应用日志测试" "FAIL"
    fi
    
    # 检查 Nginx 访问日志
    if docker logs qaup-nginx --tail 10 &>/dev/null; then
        record_test_result "Nginx日志测试" "PASS"
    else
        record_test_result "Nginx日志测试" "FAIL"
    fi
    
    # 检查日志目录
    if [ -d "$PROJECT_ROOT/logs" ]; then
        record_test_result "日志目录检查" "PASS"
    else
        record_test_result "日志目录检查" "FAIL"
    fi
}

# 测试监控功能
test_monitoring() {
    print_message $BLUE "测试监控功能..."
    
    # 测试监控脚本
    if [ -x "$PROJECT_ROOT/docker/monitor.sh" ]; then
        if "$PROJECT_ROOT/docker/monitor.sh" status &>/dev/null; then
            record_test_result "监控脚本测试" "PASS"
        else
            record_test_result "监控脚本测试" "FAIL"
        fi
    else
        record_test_result "监控脚本存在性检查" "FAIL"
    fi
    
    # 测试告警功能
    if [ -x "$PROJECT_ROOT/docker/alert-manager.sh" ]; then
        if "$PROJECT_ROOT/docker/alert-manager.sh" check &>/dev/null; then
            record_test_result "告警功能测试" "PASS"
        else
            record_test_result "告警功能测试" "FAIL"
        fi
    else
        record_test_result "告警脚本存在性检查" "FAIL"
    fi
}

# 测试备份功能
test_backup_functionality() {
    print_message $BLUE "测试备份功能..."
    
    # 测试数据库备份
    if [ -x "$PROJECT_ROOT/docker/backup-restore.sh" ]; then
        if "$PROJECT_ROOT/docker/backup-restore.sh" database &>/dev/null; then
            record_test_result "数据库备份测试" "PASS"
        else
            record_test_result "数据库备份测试" "FAIL"
        fi
    else
        record_test_result "备份脚本存在性检查" "FAIL"
    fi
    
    # 检查备份目录
    if [ -d "$PROJECT_ROOT/backup" ]; then
        record_test_result "备份目录检查" "PASS"
    else
        record_test_result "备份目录检查" "FAIL"
    fi
}

# 性能测试
test_performance() {
    print_message $BLUE "测试系统性能..."
    
    # 测试并发请求
    local concurrent_requests=10
    local total_requests=100
    
    print_message $BLUE "执行并发性能测试 ($concurrent_requests 并发, $total_requests 请求)..."
    
    # 使用 curl 进行简单的并发测试
    local start_time=$(date +%s.%N)
    
    for ((i=1; i<=concurrent_requests; i++)); do
        {
            for ((j=1; j<=10; j++)); do
                curl -s http://localhost/health &>/dev/null
            done
        } &
    done
    
    wait
    
    local end_time=$(date +%s.%N)
    local duration=$(echo "$end_time - $start_time" | bc)
    local rps=$(echo "scale=2; $total_requests / $duration" | bc)
    
    print_message $BLUE "性能测试结果: ${rps} 请求/秒"
    
    # 判断性能是否合格（简单阈值）
    if (( $(echo "$rps > 50" | bc -l) )); then
        record_test_result "并发性能测试" "PASS"
    else
        record_test_result "并发性能测试" "FAIL"
    fi
    
    # 测试内存使用
    local memory_usage=$(docker stats --no-stream --format "{{.MemPerc}}" qaup-app | sed 's/%//')
    if (( $(echo "$memory_usage < 80" | bc -l) )); then
        record_test_result "内存使用测试" "PASS"
        print_message $BLUE "应用内存使用: ${memory_usage}%"
    else
        record_test_result "内存使用测试" "FAIL"
        print_message $YELLOW "应用内存使用较高: ${memory_usage}%"
    fi
}

# 安全测试
test_security() {
    print_message $BLUE "测试安全配置..."
    
    # 测试端口访问限制
    local restricted_ports=("5432" "6379" "8080")
    
    for port in "${restricted_ports[@]}"; do
        if ! nc -z localhost "$port" 2>/dev/null; then
            record_test_result "端口${port}访问限制测试" "PASS"
        else
            record_test_result "端口${port}访问限制测试" "FAIL"
        fi
    done
    
    # 测试 HTTP 安全头
    local security_headers=("X-Frame-Options" "X-Content-Type-Options" "X-XSS-Protection")
    
    for header in "${security_headers[@]}"; do
        if curl -I -s http://localhost/ | grep -q "$header"; then
            record_test_result "${header}安全头测试" "PASS"
        else
            record_test_result "${header}安全头测试" "FAIL"
        fi
    done
}

# 运行完整集成测试
run_full_integration_test() {
    print_message $GREEN "========================================="
    print_message $GREEN "开始 QAUP 系统集成测试"
    print_message $GREEN "========================================="
    
    # 确保日志目录存在
    mkdir -p "$(dirname "$TEST_LOG")"
    
    # 记录测试开始时间
    local start_time=$(date +%s)
    
    # 执行各项测试
    test_docker_environment
    test_container_startup
    test_service_health
    test_network_connectivity
    test_database_functionality
    test_redis_functionality
    test_application_api
    test_frontend_access
    test_data_persistence
    test_file_upload
    test_logging
    test_monitoring
    test_backup_functionality
    test_performance
    test_security
    
    # 计算测试时间
    local end_time=$(date +%s)
    local duration=$((end_time - start_time))
    
    # 生成测试报告
    generate_test_report "$duration"
}

# 生成测试报告
generate_test_report() {
    local duration=$1
    
    print_message $GREEN "========================================="
    print_message $GREEN "集成测试完成"
    print_message $GREEN "========================================="
    
    echo ""
    print_message $BLUE "测试统计:"
    echo "  总测试数: $TOTAL_TESTS"
    echo "  通过测试: $PASSED_TESTS"
    echo "  失败测试: $FAILED_TESTS"
    echo "  成功率: $(echo "scale=2; $PASSED_TESTS * 100 / $TOTAL_TESTS" | bc)%"
    echo "  测试时间: ${duration}秒"
    echo ""
    
    if [ $FAILED_TESTS -eq 0 ]; then
        print_message $GREEN "🎉 所有测试通过！系统部署成功！"
        echo ""
        print_message $BLUE "系统已准备就绪，可以投入使用："
        echo "  前端访问: http://localhost"
        echo "  API 文档: http://localhost/prod-api/swagger-ui.html"
        echo "  监控面板: ./docker/monitor.sh watch"
        echo ""
    else
        print_message $RED "❌ 部分测试失败，需要检查以下问题："
        echo ""
        for failed_test in "${FAILED_TEST_NAMES[@]}"; do
            echo "  - $failed_test"
        done
        echo ""
        print_message $YELLOW "建议操作:"
        echo "  1. 查看详细日志: $TEST_LOG"
        echo "  2. 检查服务状态: ./docker/monitor.sh status"
        echo "  3. 查看容器日志: docker logs <container_name>"
        echo "  4. 修复问题后重新运行测试"
        echo ""
    fi
    
    # 创建 JSON 格式的测试报告
    local report_file="$PROJECT_ROOT/logs/integration_test_report_$(date +%Y%m%d_%H%M%S).json"
    
    cat > "$report_file" << EOF
{
  "test_run": {
    "timestamp": "$(date -u '+%Y-%m-%dT%H:%M:%S.%3NZ')",
    "duration_seconds": $duration,
    "total_tests": $TOTAL_TESTS,
    "passed_tests": $PASSED_TESTS,
    "failed_tests": $FAILED_TESTS,
    "success_rate": $(echo "scale=4; $PASSED_TESTS / $TOTAL_TESTS" | bc),
    "status": "$([ $FAILED_TESTS -eq 0 ] && echo "SUCCESS" || echo "FAILURE")"
  },
  "failed_tests": [
$(IFS=','; printf '    "%s"' "${FAILED_TEST_NAMES[*]}" | sed 's/","/",\n    "/g')
  ],
  "log_file": "$TEST_LOG",
  "report_file": "$report_file"
}
EOF
    
    print_message $BLUE "详细测试报告已生成:"
    echo "  日志文件: $TEST_LOG"
    echo "  JSON报告: $report_file"
    
    # 返回测试结果
    return $FAILED_TESTS
}

# 快速健康检查
quick_health_check() {
    print_message $BLUE "执行快速健康检查..."
    
    test_container_startup
    test_service_health
    test_frontend_access
    
    if [ $FAILED_TESTS -eq 0 ]; then
        print_message $GREEN "✓ 快速健康检查通过"
        return 0
    else
        print_message $RED "✗ 快速健康检查失败"
        return 1
    fi
}

# 显示帮助信息
show_help() {
    echo "QAUP 集成测试脚本"
    echo ""
    echo "用法: $0 [命令]"
    echo ""
    echo "命令:"
    echo "  full        运行完整集成测试"
    echo "  quick       快速健康检查"
    echo "  docker      测试 Docker 环境"
    echo "  containers  测试容器状态"
    echo "  health      测试服务健康状态"
    echo "  network     测试网络连通性"
    echo "  database    测试数据库功能"
    echo "  redis       测试 Redis 功能"
    echo "  api         测试应用 API"
    echo "  frontend    测试前端访问"
    echo "  performance 性能测试"
    echo "  security    安全测试"
    echo ""
    echo "示例:"
    echo "  $0 full         # 运行完整集成测试"
    echo "  $0 quick        # 快速健康检查"
    echo "  $0 performance  # 仅运行性能测试"
}

# 主函数
main() {
    if [ $# -eq 0 ]; then
        show_help
        exit 0
    fi
    
    local command=$1
    
    case $command in
        full)
            run_full_integration_test
            ;;
        quick)
            quick_health_check
            ;;
        docker)
            test_docker_environment
            generate_test_report 0
            ;;
        containers)
            test_container_startup
            generate_test_report 0
            ;;
        health)
            test_service_health
            generate_test_report 0
            ;;
        network)
            test_network_connectivity
            generate_test_report 0
            ;;
        database)
            test_database_functionality
            generate_test_report 0
            ;;
        redis)
            test_redis_functionality
            generate_test_report 0
            ;;
        api)
            test_application_api
            generate_test_report 0
            ;;
        frontend)
            test_frontend_access
            generate_test_report 0
            ;;
        performance)
            test_performance
            generate_test_report 0
            ;;
        security)
            test_security
            generate_test_report 0
            ;;
        help|--help|-h)
            show_help
            ;;
        *)
            print_message $RED "未知命令: $command"
            show_help
            exit 1
            ;;
    esac
    
    # 返回失败测试数量作为退出码
    exit $FAILED_TESTS
}

main "$@"