#!/bin/bash
# 环境配置管理脚本 (env-config.sh)
# 实现环境变量配置管理、支持不同环境的参数切换、添加配置验证功能
# Requirements: 6.1, 6.2, 6.3, 6.4

set -e

# 脚本目录和项目路径
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOCKER_DIR="$(dirname "$SCRIPT_DIR")"
PROJECT_ROOT="$(dirname "$DOCKER_DIR")"
ENVIRONMENTS_DIR="${DOCKER_DIR}/environments"
CONFIGS_DIR="${DOCKER_DIR}/configs"

# 颜色定义
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

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

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

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

log_debug() {
    echo -e "${BLUE}[DEBUG]${NC} $1"
}

log_success() {
    echo -e "${CYAN}[SUCCESS]${NC} $1"
}

# 显示帮助信息
show_help() {
    cat << EOF
环境配置管理脚本 - 若依框架Docker部署

用法: $0 [命令] [环境] [选项]

命令:
    validate    验证环境配置文件
    switch      切换到指定环境配置
    show        显示环境配置信息
    compare     比较不同环境配置
    backup      备份当前环境配置
    restore     恢复环境配置
    template    生成环境配置模板
    check       检查配置完整性
    list        列出所有可用环境
    help        显示此帮助信息

环境:
    development (dev)    开发环境
    staging     (stage)  测试环境
    production  (prod)   生产环境

选项:
    --force     强制执行操作（跳过确认）
    --verbose   详细输出模式
    --dry-run   预览模式（不实际执行）

示例:
    $0 validate development     # 验证开发环境配置
    $0 switch production        # 切换到生产环境
    $0 show staging            # 显示测试环境配置
    $0 compare dev prod        # 比较开发和生产环境配置
    $0 backup                  # 备份当前配置
    $0 template development    # 生成开发环境配置模板

EOF
}

# 验证环境参数
validate_environment() {
    local env=$1
    case $env in
        development|dev)
            echo "development"
            ;;
        staging|stage)
            echo "staging"
            ;;
        production|prod)
            echo "production"
            ;;
        *)
            log_error "无效的环境: $env"
            log_info "支持的环境: development, staging, production"
            exit 1
            ;;
    esac
}

# 获取环境配置文件路径
get_env_file() {
    local env=$1
    echo "${ENVIRONMENTS_DIR}/.env.${env}"
}

# 获取当前活动的环境配置文件路径
get_active_env_file() {
    echo "${DOCKER_DIR}/.env"
}

# 检查环境配置文件是否存在
check_env_file_exists() {
    local env=$1
    local env_file=$(get_env_file $env)
    
    if [ ! -f "$env_file" ]; then
        log_error "环境配置文件不存在: $env_file"
        return 1
    fi
    return 0
}

# 验证环境配置文件 (Requirements 6.1, 6.2, 6.3, 6.4)
validate_env_config() {
    local env=$1
    local env_file=$(get_env_file $env)
    local errors=0
    
    log_info "验证 $env 环境配置文件: $env_file"
    
    if ! check_env_file_exists $env; then
        return 1
    fi
    
    # 必需的配置项列表
    local required_vars=(
        "ENVIRONMENT"
        "COMPOSE_PROJECT_NAME"
        "DB_HOST"
        "DB_PORT"
        "DB_NAME"
        "DB_USER"
        "DB_PASSWORD"
        "MYSQL_ROOT_PASSWORD"
        "BACKEND_PORT"
        "FRONTEND_PORT"
        "SPRING_PROFILES_ACTIVE"
        "API_BASE_URL"
        "LOG_LEVEL"
        "NETWORK_NAME"
        "MYSQL_DATA_PATH"
    )
    
    # 检查必需的环境变量
    log_debug "检查必需的环境变量..."
    for var in "${required_vars[@]}"; do
        if ! grep -q "^${var}=" "$env_file"; then
            log_error "缺少必需的环境变量: $var"
            ((errors++))
        else
            local value=$(grep "^${var}=" "$env_file" | cut -d'=' -f2-)
            if [ -z "$value" ] || [ "$value" = "CHANGE_ME_PRODUCTION_PASSWORD" ] || [ "$value" = "CHANGE_ME_ROOT_PASSWORD" ]; then
                log_warn "环境变量 $var 需要设置有效值"
                ((errors++))
            fi
        fi
    done
    
    # 验证数据库连接配置 (Requirement 6.1)
    log_debug "验证数据库连接配置..."
    local db_port=$(grep "^DB_PORT=" "$env_file" | cut -d'=' -f2)
    if [ -n "$db_port" ] && ! [[ "$db_port" =~ ^[0-9]+$ ]]; then
        log_error "DB_PORT 必须是数字: $db_port"
        ((errors++))
    fi
    
    # 验证前端API基础URL配置 (Requirement 6.2)
    log_debug "验证前端API基础URL配置..."
    local api_url=$(grep "^API_BASE_URL=" "$env_file" | cut -d'=' -f2)
    if [ -n "$api_url" ] && ! [[ "$api_url" =~ ^https?:// ]]; then
        log_error "API_BASE_URL 必须是有效的HTTP/HTTPS URL: $api_url"
        ((errors++))
    fi
    
    # 验证容器资源限制配置 (Requirement 6.3)
    log_debug "验证容器资源限制配置..."
    local memory_vars=("FRONTEND_MEMORY_LIMIT" "BACKEND_MEMORY_LIMIT" "DATABASE_MEMORY_LIMIT")
    for var in "${memory_vars[@]}"; do
        local value=$(grep "^${var}=" "$env_file" | cut -d'=' -f2)
        if [ -n "$value" ] && ! [[ "$value" =~ ^[0-9]+$ ]]; then
            log_error "$var 必须是数字 (MB): $value"
            ((errors++))
        fi
    done
    
    local cpu_vars=("FRONTEND_CPU_LIMIT" "BACKEND_CPU_LIMIT" "DATABASE_CPU_LIMIT")
    for var in "${cpu_vars[@]}"; do
        local value=$(grep "^${var}=" "$env_file" | cut -d'=' -f2)
        if [ -n "$value" ] && ! [[ "$value" =~ ^[0-9]+\.?[0-9]*$ ]]; then
            log_error "$var 必须是有效的CPU限制值: $value"
            ((errors++))
        fi
    done
    
    # 验证日志级别和输出路径配置 (Requirement 6.4)
    log_debug "验证日志配置..."
    local log_level=$(grep "^LOG_LEVEL=" "$env_file" | cut -d'=' -f2)
    if [ -n "$log_level" ] && ! [[ "$log_level" =~ ^(DEBUG|INFO|WARN|ERROR)$ ]]; then
        log_error "LOG_LEVEL 必须是 DEBUG, INFO, WARN 或 ERROR: $log_level"
        ((errors++))
    fi
    
    local log_path=$(grep "^LOG_PATH=" "$env_file" | cut -d'=' -f2)
    if [ -n "$log_path" ] && [[ "$log_path" =~ ^/ ]] && [ ! -d "$(dirname "$log_path")" ]; then
        log_warn "日志路径的父目录不存在: $(dirname "$log_path")"
    fi
    
    # 验证网络配置
    log_debug "验证网络配置..."
    local subnet=$(grep "^SUBNET=" "$env_file" | cut -d'=' -f2)
    if [ -n "$subnet" ] && ! [[ "$subnet" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]]; then
        log_error "SUBNET 必须是有效的CIDR格式: $subnet"
        ((errors++))
    fi
    
    # 验证端口配置
    log_debug "验证端口配置..."
    local ports=("BACKEND_PORT" "FRONTEND_PORT" "DB_PORT")
    for port_var in "${ports[@]}"; do
        local port=$(grep "^${port_var}=" "$env_file" | cut -d'=' -f2)
        if [ -n "$port" ]; then
            if ! [[ "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
                log_error "$port_var 必须是1-65535之间的数字: $port"
                ((errors++))
            fi
        fi
    done
    
    # 报告验证结果
    if [ $errors -eq 0 ]; then
        log_success "$env 环境配置验证通过"
        return 0
    else
        log_error "$env 环境配置验证失败，发现 $errors 个错误"
        return 1
    fi
}

# 切换环境配置
switch_environment() {
    local env=$1
    local force=${2:-false}
    local dry_run=${3:-false}
    
    log_info "切换到 $env 环境配置..."
    
    # 验证目标环境配置
    if ! validate_env_config $env; then
        log_error "目标环境配置验证失败，无法切换"
        return 1
    fi
    
    local source_file=$(get_env_file $env)
    local target_file=$(get_active_env_file)
    
    # 备份当前配置
    if [ -f "$target_file" ] && [ "$force" != "true" ]; then
        local backup_file="${target_file}.backup.$(date +%Y%m%d_%H%M%S)"
        if [ "$dry_run" != "true" ]; then
            cp "$target_file" "$backup_file"
            log_info "当前配置已备份到: $backup_file"
        else
            log_info "[DRY-RUN] 将备份当前配置到: $backup_file"
        fi
    fi
    
    # 复制环境配置
    if [ "$dry_run" != "true" ]; then
        cp "$source_file" "$target_file"
        log_success "已切换到 $env 环境配置"
        
        # 显示关键配置信息
        show_key_config "$env"
    else
        log_info "[DRY-RUN] 将复制 $source_file 到 $target_file"
    fi
}

# 显示环境配置信息
show_env_config() {
    local env=$1
    local env_file=$(get_env_file $env)
    
    if ! check_env_file_exists $env; then
        return 1
    fi
    
    log_info "显示 $env 环境配置:"
    echo "----------------------------------------"
    
    # 显示关键配置项
    local key_vars=(
        "ENVIRONMENT"
        "COMPOSE_PROJECT_NAME"
        "DB_NAME"
        "DB_USER"
        "BACKEND_PORT"
        "FRONTEND_PORT"
        "API_BASE_URL"
        "LOG_LEVEL"
        "SPRING_PROFILES_ACTIVE"
    )
    
    for var in "${key_vars[@]}"; do
        local value=$(grep "^${var}=" "$env_file" | cut -d'=' -f2-)
        if [ -n "$value" ]; then
            printf "%-25s: %s\n" "$var" "$value"
        fi
    done
    
    echo "----------------------------------------"
}

# 显示关键配置信息
show_key_config() {
    local env=$1
    local env_file=$(get_env_file $env)
    
    echo
    log_info "当前环境关键配置:"
    echo "  环境: $(grep "^ENVIRONMENT=" "$env_file" | cut -d'=' -f2)"
    echo "  项目: $(grep "^COMPOSE_PROJECT_NAME=" "$env_file" | cut -d'=' -f2)"
    echo "  前端端口: $(grep "^FRONTEND_PORT=" "$env_file" | cut -d'=' -f2)"
    echo "  后端端口: $(grep "^BACKEND_PORT=" "$env_file" | cut -d'=' -f2)"
    echo "  数据库: $(grep "^DB_NAME=" "$env_file" | cut -d'=' -f2)"
    echo "  日志级别: $(grep "^LOG_LEVEL=" "$env_file" | cut -d'=' -f2)"
    echo
}

# 比较不同环境配置
compare_environments() {
    local env1=$1
    local env2=$2
    
    log_info "比较 $env1 和 $env2 环境配置..."
    
    if ! check_env_file_exists $env1 || ! check_env_file_exists $env2; then
        return 1
    fi
    
    local file1=$(get_env_file $env1)
    local file2=$(get_env_file $env2)
    
    echo "=========================================="
    echo "配置差异 ($env1 vs $env2):"
    echo "=========================================="
    
    # 使用diff命令比较文件
    if command -v diff &> /dev/null; then
        diff -u "$file1" "$file2" || true
    else
        log_warn "diff命令不可用，使用基本比较"
        
        # 基本比较逻辑
        local vars1=$(grep "^[A-Z]" "$file1" | cut -d'=' -f1 | sort)
        local vars2=$(grep "^[A-Z]" "$file2" | cut -d'=' -f1 | sort)
        
        # 找出差异变量
        local all_vars=$(echo -e "$vars1\n$vars2" | sort -u)
        
        for var in $all_vars; do
            local val1=$(grep "^${var}=" "$file1" | cut -d'=' -f2- 2>/dev/null || echo "")
            local val2=$(grep "^${var}=" "$file2" | cut -d'=' -f2- 2>/dev/null || echo "")
            
            if [ "$val1" != "$val2" ]; then
                printf "%-25s: %-20s | %s\n" "$var" "$val1" "$val2"
            fi
        done
    fi
    
    echo "=========================================="
}

# 备份环境配置
backup_config() {
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local backup_dir="${DOCKER_DIR}/backups/config_${timestamp}"
    
    log_info "备份环境配置到: $backup_dir"
    
    mkdir -p "$backup_dir"
    
    # 备份所有环境配置文件
    cp -r "$ENVIRONMENTS_DIR" "$backup_dir/"
    
    # 备份当前活动配置
    if [ -f "$(get_active_env_file)" ]; then
        cp "$(get_active_env_file)" "$backup_dir/active.env"
    fi
    
    # 创建备份信息文件
    cat > "$backup_dir/backup_info.txt" << EOF
备份时间: $(date)
备份内容: 环境配置文件
备份路径: $backup_dir
当前环境: $(grep "^ENVIRONMENT=" "$(get_active_env_file)" 2>/dev/null | cut -d'=' -f2 || echo "未知")
EOF
    
    log_success "配置备份完成: $backup_dir"
}

# 恢复环境配置
restore_config() {
    local backup_path=$1
    
    if [ -z "$backup_path" ]; then
        log_error "请指定备份路径"
        return 1
    fi
    
    if [ ! -d "$backup_path" ]; then
        log_error "备份路径不存在: $backup_path"
        return 1
    fi
    
    log_info "从备份恢复环境配置: $backup_path"
    
    # 确认操作
    read -p "确认恢复配置? 这将覆盖当前配置 (y/N): " -n 1 -r
    echo
    
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        # 恢复环境配置目录
        if [ -d "$backup_path/environments" ]; then
            cp -r "$backup_path/environments/"* "$ENVIRONMENTS_DIR/"
            log_info "环境配置文件已恢复"
        fi
        
        # 恢复活动配置
        if [ -f "$backup_path/active.env" ]; then
            cp "$backup_path/active.env" "$(get_active_env_file)"
            log_info "活动配置文件已恢复"
        fi
        
        log_success "配置恢复完成"
    else
        log_info "取消恢复操作"
    fi
}

# 生成环境配置模板
generate_template() {
    local env=$1
    local template_file="${ENVIRONMENTS_DIR}/.env.${env}.template"
    
    log_info "生成 $env 环境配置模板: $template_file"
    
    cat > "$template_file" << EOF
# $env 环境配置模板
# 复制此文件为 .env.$env 并根据实际环境修改配置

ENVIRONMENT=$env
COMPOSE_PROJECT_NAME=anxin-$env

# 数据库配置 (Requirement 6.1)
DB_HOST=anxin-mysql
DB_PORT=3306
DB_NAME=anxin_$env
DB_USER=anxin_$env
DB_PASSWORD=CHANGE_ME_PASSWORD
MYSQL_ROOT_PASSWORD=CHANGE_ME_ROOT_PASSWORD

# 后端服务配置
BACKEND_PORT=8080
SPRING_PROFILES_ACTIVE=$env
JAVA_OPTS=-Xms512m -Xmx1024m

# 前端服务配置 (Requirement 6.2)
FRONTEND_PORT=80
API_BASE_URL=http://localhost:8080

# 容器资源配置 (Requirement 6.3)
FRONTEND_MEMORY_LIMIT=256
BACKEND_MEMORY_LIMIT=1024
DATABASE_MEMORY_LIMIT=512

FRONTEND_CPU_LIMIT=0.5
BACKEND_CPU_LIMIT=1.0
DATABASE_CPU_LIMIT=0.5

# 日志配置 (Requirement 6.4)
LOG_LEVEL=INFO
LOG_PATH=./logs/$env
LOG_MAX_SIZE=100MB
LOG_MAX_FILES=10

# 网络配置
NETWORK_NAME=anxin-$env-network
SUBNET=172.20.0.0/16

# 卷配置
MYSQL_DATA_PATH=./data/$env/mysql
LOG_DATA_PATH=./data/$env/logs
CONFIG_DATA_PATH=./data/$env/configs
EOF
    
    log_success "模板生成完成: $template_file"
}

# 检查配置完整性
check_config_integrity() {
    log_info "检查所有环境配置完整性..."
    
    local environments=("development" "staging" "production")
    local total_errors=0
    
    for env in "${environments[@]}"; do
        echo
        if validate_env_config $env; then
            log_success "$env 环境配置完整"
        else
            ((total_errors++))
        fi
    done
    
    echo
    if [ $total_errors -eq 0 ]; then
        log_success "所有环境配置检查通过"
        return 0
    else
        log_error "发现 $total_errors 个环境配置问题"
        return 1
    fi
}

# 列出所有可用环境
list_environments() {
    log_info "可用环境配置:"
    
    for env_file in "$ENVIRONMENTS_DIR"/.env.*; do
        if [ -f "$env_file" ] && [[ ! "$env_file" =~ \.template$ ]] && [[ ! "$env_file" =~ \.example$ ]]; then
            local env_name=$(basename "$env_file" | sed 's/^\.env\.//')
            local env_desc=""
            
            case $env_name in
                development)
                    env_desc="开发环境"
                    ;;
                staging)
                    env_desc="测试环境"
                    ;;
                production)
                    env_desc="生产环境"
                    ;;
                *)
                    env_desc="自定义环境"
                    ;;
            esac
            
            printf "  %-12s - %s\n" "$env_name" "$env_desc"
            
            # 显示关键信息
            if [ -f "$env_file" ]; then
                local project=$(grep "^COMPOSE_PROJECT_NAME=" "$env_file" | cut -d'=' -f2)
                local frontend_port=$(grep "^FRONTEND_PORT=" "$env_file" | cut -d'=' -f2)
                local backend_port=$(grep "^BACKEND_PORT=" "$env_file" | cut -d'=' -f2)
                printf "    项目: %s, 前端: %s, 后端: %s\n" "$project" "$frontend_port" "$backend_port"
            fi
        fi
    done
    
    echo
    
    # 显示当前活动环境
    local active_file=$(get_active_env_file)
    if [ -f "$active_file" ]; then
        local current_env=$(grep "^ENVIRONMENT=" "$active_file" | cut -d'=' -f2)
        log_info "当前活动环境: $current_env"
    else
        log_warn "未找到活动环境配置"
    fi
}

# 解析命令行参数
parse_args() {
    FORCE=false
    VERBOSE=false
    DRY_RUN=false
    
    while [[ $# -gt 0 ]]; do
        case $1 in
            --force)
                FORCE=true
                shift
                ;;
            --verbose)
                VERBOSE=true
                shift
                ;;
            --dry-run)
                DRY_RUN=true
                shift
                ;;
            *)
                break
                ;;
        esac
    done
    
    COMMAND=$1
    ENVIRONMENT=$2
    ENVIRONMENT2=$3
}

# 主函数
main() {
    parse_args "$@"
    
    case $COMMAND in
        validate)
            if [ -z "$ENVIRONMENT" ]; then
                log_error "请指定环境"
                show_help
                exit 1
            fi
            env=$(validate_environment "$ENVIRONMENT")
            validate_env_config "$env"
            ;;
        switch)
            if [ -z "$ENVIRONMENT" ]; then
                log_error "请指定环境"
                show_help
                exit 1
            fi
            env=$(validate_environment "$ENVIRONMENT")
            switch_environment "$env" "$FORCE" "$DRY_RUN"
            ;;
        show)
            if [ -z "$ENVIRONMENT" ]; then
                log_error "请指定环境"
                show_help
                exit 1
            fi
            env=$(validate_environment "$ENVIRONMENT")
            show_env_config "$env"
            ;;
        compare)
            if [ -z "$ENVIRONMENT" ] || [ -z "$ENVIRONMENT2" ]; then
                log_error "请指定两个环境进行比较"
                show_help
                exit 1
            fi
            env1=$(validate_environment "$ENVIRONMENT")
            env2=$(validate_environment "$ENVIRONMENT2")
            compare_environments "$env1" "$env2"
            ;;
        backup)
            backup_config
            ;;
        restore)
            restore_config "$ENVIRONMENT"
            ;;
        template)
            if [ -z "$ENVIRONMENT" ]; then
                log_error "请指定环境"
                show_help
                exit 1
            fi
            env=$(validate_environment "$ENVIRONMENT")
            generate_template "$env"
            ;;
        check)
            check_config_integrity
            ;;
        list)
            list_environments
            ;;
        help|--help|-h)
            show_help
            ;;
        *)
            log_error "未知命令: $COMMAND"
            show_help
            exit 1
            ;;
    esac
}

# 检查必要的目录
if [ ! -d "$ENVIRONMENTS_DIR" ]; then
    log_error "环境配置目录不存在: $ENVIRONMENTS_DIR"
    exit 1
fi

# 执行主函数
main "$@"