#!/bin/bash
################################################################################
# Redis基础检测模块
# 功能: 检测Redis容器状态、版本、键数量、内存使用、连接数等
# 作者: Claude Code
# 日期: 2026-05-09
################################################################################

# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"

# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
    source "$LIB_DIR/lib/config.sh"
else
    echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
    exit 1
fi

if [ -f "$LIB_DIR/lib/common.sh" ]; then
    source "$LIB_DIR/lib/common.sh"
else
    echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
    exit 1
fi

# Redis容器名称
REDIS_CONTAINER="${CONTAINERS[redis]}"

# ==================== 辅助函数 ====================

# 在Redis容器中执行命令
redis_exec() {
    docker exec "$REDIS_CONTAINER" redis-cli -a "$REDIS_PASSWORD" $@ 2>&1 | grep -v "Warning:"
}

# ==================== 检测函数 ====================

# 检测Redis容器状态（使用模糊匹配）
check_redis_container() {
    local container_status="未运行"
    local level="严重"
    local matched_container=""

    if command -v docker &> /dev/null; then
        # 尝试精确匹配
        matched_container=$(docker ps --format "{{.Names}}" | grep -x "${REDIS_CONTAINER}" | head -1)

        # 如果精确匹配失败，尝试模糊匹配
        if [ -z "$matched_container" ] && [ -n "$REDIS_CONTAINER" ]; then
            matched_container=$(docker ps --format "{{.Names}}" | grep -i "${REDIS_CONTAINER}" | head -1)
        fi

        if [ -n "$matched_container" ]; then
            container_status="运行中 (${matched_container})"
            level="正常"
            # 更新全局变量
            eval "REDIS_CONTAINER='${matched_container}'"
        else
            # 检查容器是否存在但未运行
            matched_container=$(docker ps -a --format "{{.Names}}" | grep -i "${REDIS_CONTAINER}" | head -1)
            if [ -n "$matched_container" ]; then
                container_status="已停止 (${matched_container})"
                level="警告"
            fi
        fi
    fi

    output_result "REDIS_CONTAINER_STATUS" "$container_status"
    output_result "REDIS_CONTAINER_LEVEL" "$level"

    if [ "$level" != "正常" ]; then
        echo "ERROR:Redis容器${container_status}"
        return 1
    fi

    return 0
}

# 检测Redis版本
check_redis_version() {
    local version=""

    version=$(redis_exec "INFO server" | grep "redis_version" | awk -F: '{print $2}' | tr -d '\r')

    if [ -n "$version" ]; then
        output_result "REDIS_VERSION" "$version"
    else
        output_result "REDIS_VERSION" "获取失败"
    fi
}

# 检测Redis连接状态
check_redis_connection() {
    local connected="否"

    if redis_exec "PING" | grep -q "PONG"; then
        connected="是"
    fi

    output_result "REDIS_CONNECTED" "$connected"

    if [ "$connected" = "否" ]; then
        output_result "REDIS_CONNECTION_LEVEL" "严重"
        echo "ERROR:Redis连接失败"
    else
        output_result "REDIS_CONNECTION_LEVEL" "正常"
    fi
}

# 检测Redis运行时间
check_redis_uptime() {
    local uptime_days=""

    uptime_days=$(redis_exec "INFO server" | grep "uptime_in_days" | awk -F: '{print $2}' | tr -d '\r')

    if [ -n "$uptime_days" ]; then
        output_result "REDIS_UPTIME_DAYS" "${uptime_days}天"
    else
        output_result "REDIS_UPTIME_DAYS" "未知"
    fi
}

# 检测Redis键数量
check_redis_keys() {
    local key_count=""

    key_count=$(redis_exec "DBSIZE")

    if [ -n "$key_count" ] && [[ "$key_count" =~ ^[0-9]+$ ]]; then
        output_result "REDIS_KEYS" "$key_count"

        # 判断键数量状态
        local level="正常"
        if [ "$key_count" -ge 10000000 ]; then
            level="严重"
        elif [ "$key_count" -ge 1000000 ]; then
            level="警告"
        fi

        output_result "REDIS_KEYS_LEVEL" "$level"

        if [ "$level" != "正常" ]; then
            echo "ERROR:Redis键数量过多: ${key_count}"
        fi
    else
        output_result "REDIS_KEYS" "获取失败"
    fi
}

# 检测Redis内存使用
check_redis_memory() {
    local used_memory max_memory mem_fragmentation_ratio

    used_memory=$(redis_exec "INFO memory" | grep "used_memory_human:" | cut -d: -f2)
    max_memory=$(redis_exec "INFO memory" | grep "maxmemory_human:" | cut -d: -f2)
    mem_fragmentation_ratio=$(redis_exec "INFO memory" | grep "mem_fragmentation_ratio:" | cut -d: -f2)

    if [ -n "$used_memory" ]; then
        output_result "REDIS_MEMORY_USED" "$used_memory"
    fi

    if [ -n "$max_memory" ]; then
        output_result "REDIS_MEMORY_MAX" "$max_memory"
    fi

    if [ -n "$mem_fragmentation_ratio" ]; then
        output_result "REDIS_MEM_FRAGMENTATION" "$mem_fragmentation_ratio"

        # 判断内存碎片率
        local level="正常"
        local frag_value=$(echo "$mem_fragmentation_ratio" | awk '{print $1}')

        if (( $(awk "BEGIN {print ($frag_value < 1.0)}") )); then
            level="警告"  # 内存碎片过低可能表示内存不足
        elif (( $(awk "BEGIN {print ($frag_value > 1.5)}") )); then
            level="警告"  # 内存碎片过高
        fi

        output_result "REDIS_MEM_FRAG_LEVEL" "$level"
    fi

    # 获取内存使用率
    local used_memory_bytes max_memory_bytes
    used_memory_bytes=$(redis_exec "INFO memory" 2>/dev/null | grep "used_memory:" | cut -d: -f2)
    max_memory_bytes=$(redis_exec "CONFIG GET maxmemory" 2>/dev/null | tail -1)

    if [ -n "$used_memory_bytes" ] && [ -n "$max_memory_bytes" ] && [ "$max_memory_bytes" -gt 0 ]; then
        local usage_percent=$((used_memory_bytes * 100 / max_memory_bytes))
        output_result "REDIS_MEMORY_USAGE" "${usage_percent}%"

        # 判断内存使用率
        local level="正常"
        if [ "$usage_percent" -ge 90 ]; then
            level="严重"
        elif [ "$usage_percent" -ge 80 ]; then
            level="警告"
        fi

        output_result "REDIS_MEMORY_LEVEL" "$level"

        if [ "$level" != "正常" ]; then
            echo "ERROR:Redis内存使用率过高: ${usage_percent}%"
        fi
    fi
}

# 检测Redis客户端连接
check_redis_clients() {
    local connected_clients blocked_clients

    connected_clients=$(redis_exec "INFO clients" 2>/dev/null | grep "connected_clients:" | cut -d: -f2)
    blocked_clients=$(redis_exec "INFO clients" 2>/dev/null | grep "blocked_clients:" | cut -d: -f2)

    if [ -n "$connected_clients" ]; then
        output_result "REDIS_CLIENTS" "$connected_clients"
    fi

    if [ -n "$blocked_clients" ]; then
        output_result "REDIS_BLOCKED_CLIENTS" "$blocked_clients"
    fi

    # 获取最大客户端数
    local max_clients
    max_clients=$(redis_exec "CONFIG GET maxclients" 2>/dev/null | tail -1)

    if [ -n "$connected_clients" ] && [ -n "$max_clients" ]; then
        local usage_percent=$((connected_clients * 100 / max_clients))
        output_result "REDIS_CLIENTS_USAGE" "${usage_percent}%"

        # 判断连接数状态
        local level="正常"
        if [ "$usage_percent" -ge 90 ]; then
            level="严重"
        elif [ "$usage_percent" -ge 80 ]; then
            level="警告"
        fi

        output_result "REDIS_CLIENTS_LEVEL" "$level"
    fi
}

# 检测Redis持久化状态
check_redis_persistence() {
    local rdb_last_save_time aof_enabled

    rdb_last_save_time=$(redis_exec "INFO persistence" 2>/dev/null | grep "rdb_last_save_time:" | cut -d: -f2)
    aof_enabled=$(redis_exec "INFO persistence" 2>/dev/null | grep "aof_enabled:" | cut -d: -f2)

    if [ -n "$rdb_last_save_time" ]; then
        local current_time=$(date +%s)
        local rdb_age=$((current_time - rdb_last_save_time))
        local rdb_age_minutes=$((rdb_age / 60))

        output_result "REDIS_RDB_AGE" "${rdb_age_minutes}分钟"
    fi

    if [ -n "$aof_enabled" ]; then
        if [ "$aof_enabled" -eq 1 ]; then
            output_result "REDIS_AOF" "启用"
        else
            output_result "REDIS_AOF" "未启用"
        fi
    fi
}

# 检测Redis命令统计
check_redis_stats() {
    local total_connections_received total_commands_processed instantaneous_ops_per_sec

    total_connections_received=$(redis_exec "INFO stats" 2>/dev/null | grep "total_connections_received:" | cut -d: -f2)
    total_commands_processed=$(redis_exec "INFO stats" 2>/dev/null | grep "total_commands_processed:" | cut -d: -f2)
    instantaneous_ops_per_sec=$(redis_exec "INFO stats" 2>/dev/null | grep "instantaneous_ops_per_sec:" | cut -d: -f2)

    if [ -n "$total_connections_received" ]; then
        output_result "REDIS_TOTAL_CONNECTIONS" "$total_connections_received"
    fi

    if [ -n "$total_commands_processed" ]; then
        output_result "REDIS_TOTAL_COMMANDS" "$total_commands_processed"
    fi

    if [ -n "$instantaneous_ops_per_sec" ]; then
        output_result "REDIS_OPS_PER_SEC" "$instantaneous_ops_per_sec"
    fi
}

# 检测Redis命中率
check_redis_hit_rate() {
    local keyspace_hits keyspace_misses

    keyspace_hits=$(redis_exec "INFO stats" 2>/dev/null | grep "keyspace_hits:" | cut -d: -f2)
    keyspace_misses=$(redis_exec "INFO stats" 2>/dev/null | grep "keyspace_misses:" | cut -d: -f2)

    if [ -n "$keyspace_hits" ] && [ -n "$keyspace_misses" ]; then
        local total=$((keyspace_hits + keyspace_misses))

        if [ "$total" -gt 0 ]; then
            local hit_rate=$((keyspace_hits * 100 / total))
            output_result "REDIS_HIT_RATE" "${hit_rate}%"

            # 判断命中率
            local level="正常"
            if [ "$hit_rate" -lt 80 ]; then
                level="严重"
            elif [ "$hit_rate" -lt 90 ]; then
                level="警告"
            fi

            output_result "REDIS_HIT_RATE_LEVEL" "$level"
        fi
    fi
}

# 检测Redis主从状态
check_redis_replication() {
    local role connected_slaves

    role=$(redis_exec "INFO replication" 2>/dev/null | grep "role:" | cut -d: -f2)
    connected_slaves=$(redis_exec "INFO replication" 2>/dev/null | grep "connected_slaves:" | cut -d: -f2)

    if [ -n "$role" ]; then
        output_result "REDIS_ROLE" "$role"
    fi

    if [ -n "$connected_slaves" ]; then
        output_result "REDIS_SLAVES" "$connected_slaves"
    fi

    # 如果是从库，检查主库连接状态
    if [ "$role" = "slave" ]; then
        local master_link_status
        master_link_status=$(redis_exec "INFO replication" 2>/dev/null | grep "master_link_status:" | cut -d: -f2)

        if [ -n "$master_link_status" ]; then
            output_result "REDIS_MASTER_LINK" "$master_link_status"

            if [ "$master_link_status" != "up" ]; then
                output_result "REDIS_REPLICATION_LEVEL" "严重"
                echo "ERROR:Redis主从连接异常"
            else
                output_result "REDIS_REPLICATION_LEVEL" "正常"
            fi
        fi
    fi
}

# ==================== 主检测流程 ====================
main() {
    log_info "开始Redis基础检测..."

    # 检查容器状态
    if ! check_redis_container; then
        log_warn "Redis容器未运行，跳过其他检测"
        return
    fi

    # 执行各项检测
    check_redis_version
    check_redis_connection
    check_redis_uptime
    check_redis_keys
    check_redis_memory
    check_redis_clients
    check_redis_persistence
    check_redis_stats
    check_redis_hit_rate
    check_redis_replication

    log_info "Redis基础检测完成"
}

# 执行主函数
main
