#!/usr/bin/env bash
# Emergency memory pressure relief: drops caches, kills OOM candidates if needed
# Usage: memory-pressure [--force-oom-kill]

set -uo pipefail

LOG_FILE="/opt/server-resilience/logs/memory-$(date +%Y%m%d).log"
ALERT_SCRIPT="/opt/server-resilience/bin/send-alert"
FORCE_OOM="${1:-}"

mkdir -p "$(dirname "$LOG_FILE")"

RED='\033[0;31m'; YELLOW='\033[1;33m'; GREEN='\033[0;32m'; BOLD='\033[1m'; NC='\033[0m'

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }

MEM_AVAIL_MB=$(free -m | awk '/^Mem/{print $7}')
MEM_TOTAL_MB=$(free -m | awk '/^Mem/{print $2}')
SWAP_USED_MB=$(free -m | awk '/^Swap/{print $3}')
SWAP_TOTAL_MB=$(free -m | awk '/^Swap/{print $2}')

echo -e "\n${BOLD}=== Memory Pressure Relief ===${NC}"
log "=== memory-pressure run ==="
log "Before: RAM avail=${MEM_AVAIL_MB}MB, Swap used=${SWAP_USED_MB}/${SWAP_TOTAL_MB}MB"

echo "Before:"
free -m

# ─── Step 1: Drop page cache (safe, Linux will reclaim as needed) ─────────────
echo -e "\n${BOLD}Step 1: Dropping page/slab caches...${NC}"
sync
echo 3 > /proc/sys/vm/drop_caches
log "Dropped caches (echo 3 > drop_caches)"

sleep 1
MEM_AFTER_DROP=$(free -m | awk '/^Mem/{print $7}')
echo -e "${GREEN}After cache drop: ${MEM_AFTER_DROP}MB available${NC}"

# ─── Step 2: Kill zombie PHP-FPM workers if RAM still critical ───────────────
if [[ $MEM_AFTER_DROP -lt 300 ]]; then
    log "RAM still critical after cache drop — checking PHP-FPM workers"
    PHP_FPM_COUNT=$(pgrep -c "php-fpm" 2>/dev/null || echo 0)
    if [[ $PHP_FPM_COUNT -gt 20 ]]; then
        echo -e "${YELLOW}Reloading PHP-FPM (${PHP_FPM_COUNT} workers) to release idle workers...${NC}"
        systemctl reload php-fpm 2>/dev/null || true
        log "PHP-FPM reloaded (had $PHP_FPM_COUNT workers)"
        sleep 2
    fi
fi

# ─── Step 3: Check MariaDB buffer pool vs actual usage ───────────────────────
INNODB_POOL_MB=$(mysql -N -e "SELECT @@innodb_buffer_pool_size/1024/1024;" 2>/dev/null | awk '{printf "%d", $1}' || echo 0)
INNODB_USED_MB=$(mysql -N -e "SELECT (SELECT variable_value FROM information_schema.global_status WHERE variable_name='Innodb_buffer_pool_pages_data') * @@innodb_page_size / 1024 / 1024;" 2>/dev/null | awk '{printf "%d", $1}' || echo 0)

if [[ $INNODB_POOL_MB -gt 0 && $INNODB_USED_MB -gt 0 ]]; then
    POOL_EFFICIENCY=$((INNODB_USED_MB * 100 / INNODB_POOL_MB))
    echo ""
    echo "InnoDB buffer pool: ${INNODB_USED_MB}MB used / ${INNODB_POOL_MB}MB allocated (${POOL_EFFICIENCY}% efficiency)"
    log "InnoDB pool: ${INNODB_USED_MB}/${INNODB_POOL_MB}MB (${POOL_EFFICIENCY}%)"
    if [[ $POOL_EFFICIENCY -lt 50 && $INNODB_POOL_MB -gt 512 ]]; then
        echo -e "${YELLOW}InnoDB buffer pool is oversized (${POOL_EFFICIENCY}% utilized). Consider reducing in /etc/my.cnf.d/cmptv-tuning.cnf${NC}"
    fi
fi

# ─── Step 4: Emergency OOM kill if explicitly requested ──────────────────────
if [[ "$FORCE_OOM" == "--force-oom-kill" ]]; then
    MEM_FINAL=$(free -m | awk '/^Mem/{print $7}')
    if [[ $MEM_FINAL -lt 100 ]]; then
        log "FORCE_OOM_KILL: RAM=${MEM_FINAL}MB — finding top consumer"
        TOP_PID=$(ps aux --sort=-%rss 2>/dev/null | grep -v "^root\|mysqld\|httpd\|nginx\|php-fpm" | awk 'NR==2{print $2}')
        TOP_CMD=$(ps aux --sort=-%rss 2>/dev/null | grep -v "^root\|mysqld\|httpd\|nginx\|php-fpm" | awk 'NR==2{print $11}')
        if [[ -n "$TOP_PID" ]]; then
            echo -e "${RED}OOM KILL: $TOP_CMD (PID $TOP_PID)${NC}"
            kill -9 "$TOP_PID" 2>/dev/null || true
            log "OOM killed PID $TOP_PID ($TOP_CMD)"
            "$ALERT_SCRIPT" "CRITICAL" "Emergency OOM kill: $TOP_CMD (PID $TOP_PID) killed to prevent system crash" 2>/dev/null || true
        fi
    fi
fi

# ─── Final report ─────────────────────────────────────────────────────────────
echo ""
echo "After:"
free -m
MEM_FINAL=$(free -m | awk '/^Mem/{print $7}')
SWAP_FINAL=$(free -m | awk '/^Swap/{print $3}')
log "After: RAM avail=${MEM_FINAL}MB, Swap used=${SWAP_FINAL}MB"

echo ""
if [[ $MEM_FINAL -gt 500 ]]; then
    echo -e "${GREEN}Memory pressure relieved: ${MEM_FINAL}MB available${NC}"
else
    echo -e "${RED}Memory still critical: ${MEM_FINAL}MB available. Manual investigation required.${NC}"
    "$ALERT_SCRIPT" "CRITICAL" "Memory pressure unrelieved: only ${MEM_FINAL}MB available after relief attempt on $(hostname)" 2>/dev/null || true
fi
