#!/bin/bash
################################################################################
# 内存资源检测模块
# 功能: 检测内存使用率、Swap使用、NUMA架构等
# 作者: 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

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

# 检测内存使用率
check_memory_usage() {
    local mem_total mem_used mem_free mem_available usage_percent status

    # 从 free 命令获取内存信息
    read _ mem_total mem_used mem_free _ < <(free -b | grep "^Mem:")

    if [ -n "$mem_total" ] && [ "$mem_total" -gt 0 ]; then
        # 计算使用率
        usage_percent=$(awk "BEGIN {printf \"%.1f\", ($mem_used / $mem_total) * 100}")

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

        # 格式化为GB
        local total_gb=$(awk "BEGIN {printf \"%.2f\", $mem_total/1024/1024/1024}")
        local used_gb=$(awk "BEGIN {printf \"%.2f\", $mem_used/1024/1024/1024}")
        local free_gb=$(awk "BEGIN {printf \"%.2f\", $mem_free/1024/1024/1024}")

        output_result "MEMORY_USAGE" "${usage_percent}%"
        output_result "MEMORY_USED" "${used_gb}GB"
        output_result "MEMORY_FREE" "${free_gb}GB"
        output_result "MEMORY_TOTAL" "${total_gb}GB"
        output_result "MEMORY_STATUS" "$status"

        # 如果状态异常，输出错误信息
        if [ "$status" != "正常" ]; then
            echo "ERROR:内存使用率过高: ${usage_percent}%"
        fi
    else
        output_result "MEMORY_USAGE" "未知"
        output_result "MEMORY_STATUS" "未知"
    fi
}

# 检测Swap使用
check_swap_usage() {
    local swap_total swap_used swap_percent status

    # 从 free 命令获取Swap信息
    read _ swap_total swap_used _ < <(free -b | grep "^Swap:")

    if [ -n "$swap_total" ] && [ "$swap_total" -gt 0 ]; then
        if [ "$swap_used" -gt 0 ]; then
            swap_percent=$(awk "BEGIN {printf \"%.1f\", ($swap_used / $swap_total) * 100}")

            # Swap使用判断阈值
            if [ "$swap_percent" -ge 20 ]; then
                status="严重"
            elif [ "$swap_percent" -ge 1 ]; then
                status="警告"
            else
                status="正常"
            fi

            # 格式化为MB
            local swap_used_mb=$(awk "BEGIN {printf \"%.2f\", $swap_used/1024/1024}")

            output_result "SWAP_USAGE" "${swap_percent}%"
            output_result "SWAP_USED" "${swap_used_mb}MB"
            output_result "SWAP_STATUS" "$status"

            if [ "$status" != "正常" ]; then
                echo "ERROR:Swap已使用: ${swap_used_mb}MB"
            fi
        else
            output_result "SWAP_USAGE" "0%"
            output_result "SWAP_USED" "0MB"
            output_result "SWAP_STATUS" "正常"
        fi
    else
        output_result "SWAP_USAGE" "无Swap"
        output_result "SWAP_STATUS" "正常"
    fi
}

# 检测NUMA架构
check_numa() {
    if command -v numactl &> /dev/null; then
        local numa_nodes
        numa_nodes=$(numactl --hardware 2>/dev/null | grep "node(s)" | awk '{print $1}')

        if [ -n "$numa_nodes" ]; then
            output_result "NUMA_NODES" "$numa_nodes"
            output_result "NUMA_STATUS" "已启用"
        else
            output_result "NUMA_STATUS" "不支持"
        fi
    else
        output_result "NUMA_STATUS" "未安装numactl"
    fi
}

# 检测内存详情（buffers/cached）
check_memory_details() {
    local buffers cached

    # 从 /proc/meminfo 获取详细信息
    buffers=$(awk '/^Buffers:/ {print $2}' /proc/meminfo 2>/dev/null)
    cached=$(awk '/^Cached:/ {print $2}' /proc/meminfo 2>/dev/null)

    if [ -n "$buffers" ] && [ -n "$cached" ]; then
        local buffers_mb=$(awk "BEGIN {printf \"%.2f\", $buffers/1024}")
        local cached_mb=$(awk "BEGIN {printf \"%.2f\", $cached/1024}")

        output_result "MEMORY_BUFFERS" "${buffers_mb}MB"
        output_result "MEMORY_CACHED" "${cached_mb}MB"
    fi
}

# 检测内存占用TOP5进程
check_memory_top5() {
    local top5
    top5=$(ps -eo pid,comm,%mem,%cpu --no-headers 2>/dev/null | sort -k3 -rn | head -5)

    if [ -n "$top5" ]; then
        # 格式化输出
        local formatted=""
        while IFS= read -r line; do
            if [ -n "$line" ]; then
                if [ -n "$formatted" ]; then
                    formatted="${formatted}; ${line}"
                else
                    formatted="${line}"
                fi
            fi
        done <<< "$top5"

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

# 检测内存压力
check_memory_pressure() {
    if [ -f /proc/pressure/memory ]; then
        local pressure_info
        pressure_info=$(cat /proc/pressure/memory 2>/dev/null | head -1)
        if [ -n "$pressure_info" ]; then
            # 解析一些关键指标
            local avg10=$(echo "$pressure_info" | grep -oP 'avg10=\K[\d.]+' || echo "0")
            local avg60=$(echo "$pressure_info" | grep -oP 'avg60=\K[\d.]+' || echo "0")
            output_result "MEMORY_PRESSURE_AVG10" "$avg10"
            output_result "MEMORY_PRESSURE_AVG60" "$avg60"
        fi
    else
        output_result "MEMORY_PRESSURE" "不支持"
    fi
}

# 检测虚拟内存统计
check_vm_stat() {
    if [ -f /proc/vmstat ]; then
        # 获取一些关键指标
        local pgmajfault pswpin pswpout
        pgmajfault=$(awk '/pgmajfault/ {print $2}' /proc/vmstat 2>/dev/null || echo "0")
        pswpin=$(awk '/pswpin/ {print $2}' /proc/vmstat 2>/dev/null || echo "0")
        pswpout=$(awk '/pswpout/ {print $2}' /proc/vmstat 2>/dev/null || echo "0")

        output_result "VM_PGMajFAULT" "$pgmajfault"
        output_result "VM_PSWPIN" "$pswpin"
        output_result "VM_PSWPOUT" "$pswpout"
    fi
}

# 检测Slab缓存
check_slab_info() {
    if [ -f /proc/meminfo ]; then
        local slab_total slab_reclaimable
        slab_total=$(awk '/^Slab:/ {print $2}' /proc/meminfo 2>/dev/null)
        slab_reclaimable=$(awk '/^SReclaimable:/ {print $2}' /proc/meminfo 2>/dev/null)

        if [ -n "$slab_total" ]; then
            local slab_mb=$(awk "BEGIN {printf \"%.2f\", $slab_total/1024}")
            output_result "SLAB_TOTAL" "${slab_mb}MB"
        fi

        if [ -n "$slab_reclaimable" ]; then
            local reclaimable_mb=$(awk "BEGIN {printf \"%.2f\", $slab_reclaimable/1024}")
            output_result "SLAB_RECLAIMABLE" "${reclaimable_mb}MB"
        fi
    fi
}

# 检测大页内存
check_hugepages() {
    if [ -f /proc/meminfo ]; then
        local huge_total huge_free huge_size
        huge_total=$(awk '/^HugePages_Total:/ {print $2}' /proc/meminfo 2>/dev/null)
        huge_free=$(awk '/^HugePages_Free:/ {print $2}' /proc/meminfo 2>/dev/null)
        huge_size=$(awk '/^Hugepagesize:/ {print $2}' /proc/meminfo 2>/dev/null)

        output_result "HUGEPAGES_TOTAL" "${huge_total:-0}"
        output_result "HUGEPAGES_FREE" "${huge_free:-0}"
        output_result "HUGEPAGES_SIZE" "${huge_size:-未知}"

        # 检查是否启用了透明大页
        if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then
            local thp_enabled=$(cat /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null)
            output_result "TRANSPARENT_HUGEPAGE" "$thp_enabled"
        fi
    fi
}

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

    # 执行各项检测
    check_memory_usage
    check_swap_usage
    check_memory_details
    check_numa
    check_memory_top5
    check_memory_pressure
    check_vm_stat
    check_slab_info
    check_hugepages

    log_info "内存资源检测完成"
}

# 执行主函数
main
