#!/bin/bash
################################################################################
# CPU资源检测模块
# 功能: 检测CPU使用率、各核心状态、CPU占用TOP5进程
# 作者: 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

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

# 检测CPU使用率
check_cpu_usage() {
    local cpu_output user_cpu sys_cpu total_cpu status

    # 获取CPU信息
    cpu_output=$(top -bn1 | grep "Cpu(s)" 2>/dev/null)

    # 解析用户态和系统态CPU使用率
    if echo "$cpu_output" | grep -q "us"; then
        # 格式: %Cpu(s): 10.5 us,  7.0 sy,  0.0 ni, 80.7 id
        # 使用awk更可靠地解析，字段是 "us," 格式
        user_cpu=$(echo "$cpu_output" | awk '{for(i=1;i<=NF;i++) if($i=="us,") print $(i-1)}')
        sys_cpu=$(echo "$cpu_output" | awk '{for(i=1;i<=NF;i++) if($i=="sy,") print $(i-1)}')

        # 计算总使用率
        if [ -n "$user_cpu" ] && [ -n "$sys_cpu" ]; then
            total_cpu=$(awk "BEGIN {printf \"%.1f\", $user_cpu + $sys_cpu}")

            # 判断状态
            if (( $(awk "BEGIN {print ($total_cpu >= $CPU_CRITICAL)}") )); then
                status="严重"
            elif (( $(awk "BEGIN {print ($total_cpu >= $CPU_WARNING)}") )); then
                status="警告"
            else
                status="正常"
            fi

            output_result "CPU_USAGE" "${total_cpu}%"
            output_result "CPU_USER" "${user_cpu}%"
            output_result "CPU_SYSTEM" "${sys_cpu}%"
            output_result "CPU_STATUS" "$status"

            # 如果状态异常，输出错误信息
            if [ "$status" != "正常" ]; then
                echo "ERROR:CPU使用率过高: ${total_cpu}%"
            fi
        else
            output_result "CPU_USAGE" "未知"
            output_result "CPU_STATUS" "未知"
        fi
    else
        # 备用方案：从 /proc/stat 解析
        local cpu_user cpu_nice cpu_system cpu_idle cpu_total
        read cpu_user cpu_nice cpu_system cpu_idle rest < /proc/stat

        # 计算使用率（简化版）
        cpu_total=$((cpu_user + cpu_nice + cpu_system))
        local usage=$(awk "BEGIN {printf \"%.1f\", ($cpu_total / ($cpu_total + $cpu_idle)) * 100}")

        if (( $(awk "BEGIN {print ($usage >= $CPU_CRITICAL)}") )); then
            status="严重"
        elif (( $(awk "BEGIN {print ($usage >= $CPU_WARNING)}") )); then
            status="警告"
        else
            status="正常"
        fi

        output_result "CPU_USAGE" "${usage}%"
        output_result "CPU_STATUS" "$status"
    fi
}

# 检测各核心CPU使用率
check_cpu_per_core() {
    if command -v mpstat &> /dev/null; then
        local core_info
        core_info=$(mpstat -P ALL 1 1 2>/dev/null | grep -v "^$" | tail -n +4 | head -n -1)

        if [ -n "$core_info" ]; then
            output_result "CPU_PER_CORE" "已获取"
        else
            output_result "CPU_PER_CORE" "mpstat不可用"
        fi
    else
        output_result "CPU_PER_CORE" "未安装mpstat"
    fi
}

# 检测CPU占用TOP15进程
check_cpu_top15() {
    local top15
    top15=$(ps -eo pid,comm,%cpu --no-headers 2>/dev/null | sort -k3 -rn | head -15)

    if [ -n "$top15" ]; then
        # 格式化输出，只取前10个避免过长
        local formatted=""
        local count=0
        while IFS= read -r line; do
            if [ -n "$line" ] && [ $count -lt 10 ]; then
                if [ -n "$formatted" ]; then
                    formatted="${formatted}; ${line}"
                else
                    formatted="${line}"
                fi
                count=$((count + 1))
            fi
        done <<< "$top15"

        output_result "CPU_TOP10_PROCESSES" "$formatted"
    else
        output_result "CPU_TOP10_PROCESSES" "获取失败"
    fi
}

# 检测CPU上下文切换
check_cpu_context_switches() {
    local ctxt
    ctxt=$(awk '/ctxt/ {print $2}' /proc/stat 2>/dev/null)

    if [ -n "$ctxt" ]; then
        # 格式化为可读格式
        local formatted=$(echo "$ctxt" | awk '{printf "%'\''d", $0}')
        output_result "CPU_CONTEXT_SWITCHES" "$formatted"
    else
        output_result "CPU_CONTEXT_SWITCHES" "未知"
    fi
}

# 检测CPU中断
check_cpu_interrupts() {
    local intr
    intr=$(awk '/intr/ {print $2}' /proc/stat 2>/dev/null)

    if [ -n "$intr" ]; then
        # 格式化为可读格式
        local formatted=$(echo "$intr" | awk '{printf "%'\''d", $0}')
        output_result "CPU_INTERRUPTS" "$formatted"
    else
        output_result "CPU_INTERRUPTS" "未知"
    fi
}

# 检测详细中断统计(/proc/interrupts)
check_interrupts_detail() {
    if [ -f /proc/interrupts ]; then
        # 获取前10个中断的统计
        local interrupts
        interrupts=$(head -10 /proc/interrupts 2>/dev/null | grep -v "^$" | tr '\n' ',' | sed 's/,$//')
        if [ -n "$interrupts" ]; then
            output_result "IRQ_DETAIL" "$interrupts"
        fi
    fi
}

# 检测软中断统计
check_softirqs() {
    if [ -f /proc/softirqs ]; then
        local softirqs
        softirqs=$(cat /proc/softirqs 2>/dev/null | tr '\n' ',' | sed 's/,$//')
        if [ -n "$softirqs" ]; then
            output_result "SOFTIRQS" "$softirqs"
        fi
    fi
}

# 检测CPU调度器运行队列长度
check_scheduler_runqueue() {
    local runqueue
    # 新版内核 /proc/stat 格式变化，尝试多种方式获取
    runqueue=$(awk '/^procs_running/ {print $2}' /proc/stat 2>/dev/null)
    if [ -z "$runqueue" ]; then
        runqueue=$(grep -oP 'runnable\s+\K\d+' /proc/stat 2>/dev/null)
    fi

    if [ -n "$runqueue" ]; then
        output_result "SCHEDULER_RUNQUEUE" "$runqueue"
    fi
    # 无法获取时不输出
}

# 检测进程CPU亲和性示例
check_cpu_affinity() {
    # 获取init进程的CPU亲和性作为示例
    local affinity=""
    if [ -f /proc/1/status ]; then
        affinity=$(grep "Cpus_allowed_list" /proc/1/status 2>/dev/null | awk '{print $2}')
    fi

    if [ -n "$affinity" ]; then
        output_result "CPU_AFFINITY_SAMPLE" "$affinity"
    else
        output_result "CPU_AFFINITY_SAMPLE" "未知"
    fi
}

# 检测CPU调度器阻塞进程数
check_scheduler_blocked() {
    local runnables=0
    local blocked_status="正常"

    # 从/proc/stat获取可运行进程数
    runnables=$(awk '/procs_running/ {print $2}' /proc/stat 2>/dev/null)

    if [ -n "$runnables" ]; then
        output_result "SCHEDULER_PROCS_RUNNING" "$runnables"

        # 判断状态（可运行进程过多表示调度器压力大）
        if [ "$runnables" -gt 100 ]; then
            blocked_status="严重"
        elif [ "$runnables" -gt 50 ]; then
            blocked_status="警告"
        fi

        output_result "SCHEDULER_BLOCKED_STATUS" "$blocked_status"
    else
        output_result "SCHEDULER_BLOCKED_STATUS" "未知"
    fi
}

# ==================== 主检测流程 ====================
main() {
    log_info "开始CPU资源检测..."

    # 执行各项检测
    check_cpu_usage
    check_cpu_per_core
    check_cpu_top15
    check_cpu_context_switches
    check_cpu_interrupts
    check_interrupts_detail
    check_softirqs
    check_scheduler_runqueue
    check_cpu_affinity
    check_scheduler_blocked

    log_info "CPU资源检测完成"
}

# 执行主函数
main
