#!/usr/bin/env bash
# =============================================================================
# V-Connect PBX — Tuning / performance verification (READ-ONLY)
# =============================================================================
# Confirms the PHP, Asterisk-concurrency, SIP-reliability and log-rotation
# tuning is in place. Changes NOTHING — safe to run any time on any box.
#
# Usage:  sudo bash /var/www/html/scripts/verify-tuning.sh
# =============================================================================

set -uo pipefail
PASS=0; FAIL=0
ok()   { echo -e "  \033[0;32m✓\033[0m $*"; PASS=$((PASS+1)); }
bad()  { echo -e "  \033[0;31m✗\033[0m $*"; FAIL=$((FAIL+1)); }
note() { echo -e "  \033[0;36m•\033[0m $*"; }
hdr()  { echo -e "\n\033[0;34m▸ $*\033[0m"; }

ASTDB() { asterisk -rx "$1" 2>/dev/null; }

hdr "PHP runtime"
PHP_VER="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;' 2>/dev/null)"
if php -d opcache.enable_cli=1 -r 'exit(opcache_get_status(false)!==false?0:1);' 2>/dev/null; then
    ok "OPcache available and functional"
else
    bad "OPcache NOT functional — run scripts/tune-php.sh"
fi
WEBMEM="$(php -d opcache.enable_cli=1 -r 'echo ini_get("opcache.enable");' 2>/dev/null)"
[[ "$WEBMEM" == "1" ]] && ok "opcache.enable=1 (web SAPI)" || bad "opcache.enable not 1"
DROPIN="/etc/php/${PHP_VER}/mods-available/vconnect-tuning.ini"
if [[ -f "$DROPIN" ]]; then
    ML="$(grep -E '^memory_limit' "$DROPIN" | tr -d ' ' | cut -d= -f2)"
    ok "Tuning drop-in present (memory_limit=${ML:-?})"
else
    bad "Tuning drop-in missing ($DROPIN) — run scripts/tune-php.sh"
fi

hdr "Asterisk concurrency / call ceiling"
SET="$(ASTDB 'core show settings')"
echo "$SET" | grep -qiE "Maximum calls:\s+200" && ok "maxcalls=200 (live)" || note "maxcalls: $(echo "$SET" | grep -i 'Maximum calls:' | xargs)"
echo "$SET" | grep -qiE "Maximum load average:\s+4" && ok "maxload=4 (live)" || note "maxload: $(echo "$SET" | grep -i 'Maximum load' | xargs)"
SINIT="$(grep -E '^initial_size' /etc/asterisk/stasis.conf 2>/dev/null | cut -d= -f2)"
SMAX="$(grep -E '^max_size' /etc/asterisk/stasis.conf 2>/dev/null | cut -d= -f2)"
[[ "${SMAX:-0}" -ge 300 ]] && ok "stasis max_size=${SMAX} (initial=${SINIT})" || bad "stasis max_size=${SMAX:-unset} (expected >=300)"
TP="$(grep -E '^threadpool_max_size' /etc/asterisk/pjsip.conf 2>/dev/null | head -1 | cut -d= -f2)"
[[ -n "$TP" ]] && ok "pjsip threadpool_max_size=${TP}" || note "pjsip threadpool not set (using defaults)"
OD="$(grep -E 'max_connections' /etc/asterisk/res_odbc.conf 2>/dev/null | grep -oE '[0-9]+' | head -1)"
[[ "${OD:-0}" -ge 50 ]] && ok "ODBC max_connections=${OD}" || note "ODBC max_connections=${OD:-unset}"

hdr "Taskprocessor health (event bus)"
INQ="$(ASTDB 'core show taskprocessors' | awk 'NR>2 {print $3}' | sort -rn | head -1)"
[[ "${INQ:-0}" -lt 100 ]] && ok "Max in-queue depth currently ${INQ:-0} (healthy)" || note "A taskprocessor queue is at ${INQ} — watch under load"

hdr "SIP reliability"
ASTDB 'pjsip show transports' | grep -q "transport-udp" && ok "UDP transport bound" || bad "UDP transport missing"
if grep -qE '^[ \t]*external_(media|signaling)_address[ \t]*=' /etc/asterisk/pjsip.conf 2>/dev/null; then
    EXT="$(grep -E '^[ \t]*external_(media|signaling)_address[ \t]*=' /etc/asterisk/pjsip.conf | head -1 | cut -d= -f2 | tr -d ' ')"
    if ip -4 -o addr show 2>/dev/null | awk '{print $4}' | cut -d/ -f1 | grep -qx "$EXT"; then
        ok "external_* = ${EXT} (this box's own IP — fine)"
    elif [[ "$EXT" =~ ^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.) ]]; then
        bad "external_* = ${EXT} is a PRIVATE IP not on this box — STALE. Fix: run pbx:deploy, or clear it in Settings → SIP/NAT"
    else
        ok "external_* = ${EXT} (public IP — intentional for hosted/static)"
    fi
else
    ok "No external_*_address pin (symmetric RTP handles NAT — correct for LAN/dynamic-IP)"
fi
REG="$(ASTDB 'pjsip show registrations' | grep -c Registered)"
[[ "${REG:-0}" -ge 1 ]] && ok "${REG} trunk registration(s) up" || note "No trunk registrations shown"
AVAIL="$(ASTDB 'pjsip show contacts' | grep -c Avail)"
note "${AVAIL:-0} contact(s) currently Avail (qualified)"

hdr "Log rotation"
if grep -q "maxsize" /etc/logrotate.d/fail2ban 2>/dev/null; then
    ok "fail2ban rotation has a size cap ($(grep maxsize /etc/logrotate.d/fail2ban | xargs))"
else
    bad "fail2ban rotation has NO maxsize — can balloon (run scripts/tune-php.sh)"
fi
F2BSZ="$(du -m /var/log/fail2ban.log 2>/dev/null | cut -f1)"
[[ "${F2BSZ:-0}" -lt 100 ]] && ok "fail2ban.log is ${F2BSZ:-0} MB" || bad "fail2ban.log is ${F2BSZ} MB — truncate it"
grep -q "maxsize" /etc/logrotate.d/asterisk 2>/dev/null && ok "asterisk rotation has a size cap" || note "asterisk rotation: no maxsize"

hdr "System headroom"
NOFILE="$(cat /proc/$(pgrep -x asterisk | head -1)/limits 2>/dev/null | awk '/open files/{print $4}')"
[[ "${NOFILE:-0}" -ge 8192 ]] && ok "Asterisk open-files limit=${NOFILE}" || bad "open-files limit=${NOFILE:-?} (raise to >=8192)"
MAXC="$(mysql -N -u root -e "SHOW VARIABLES LIKE 'max_connections';" 2>/dev/null | awk '{print $2}')"
[[ "${MAXC:-0}" -ge 151 ]] && ok "MariaDB max_connections=${MAXC}" || note "MariaDB max_connections=${MAXC:-?}"

echo ""
echo "═══════════════════════════════════════════"
echo "  Verification: ${PASS} passed, ${FAIL} failed"
[[ "$FAIL" -eq 0 ]] && echo "  ✓ All tuning in place." || echo "  ✗ Review the ✗ items above."
echo "═══════════════════════════════════════════"
