#!/bin/bash
# ============================================================================
#  sysmon-status.sh —— GPU 机控制台监控面板「顶部状态栏」
#  由 /usr/local/bin/sysmon.sh 在 tmux 顶部窗格内启动，每 REFRESH 秒刷新。
#  配置：/etc/sysmon.conf（PORTS / UNITS / TITLE / PANEL_TZ / SYSMON_REFRESH）
#        —— 每轮刷新都重新读取，改完保存下一轮（≤5s）自动生效，无需重启面板。
#  注意：Linux 控制台无中日韩字体，故面板文案一律用 ASCII/英文。
# ============================================================================
set -u
REFRESH_DEFAULT=5
PORTS_DEFAULT="ComfyUI:8189 LLM:8080 LMStudio:1234 H3-UI:3013 H3-API:6020"
UNITS_DEFAULT="llama-bucoid-heretic llama-ridge llama-ridge-long llama-ko-ridge llama-ko-ridge-fast lmstudio"
TITLE_DEFAULT="SYS MONITOR"

R=$'\033[0m'; B=$'\033[1m'; D=$'\033[2m'
G=$'\033[32m'; RD=$'\033[31m'; Y=$'\033[33m'; C=$'\033[36m'; M=$'\033[35m'

port_up() { ss -ltnH "sport = :$1" 2>/dev/null | grep -q . ; }
trim() { sed 's/^[[:space:]]*//; s/[[:space:]]*$//' <<<"$1"; }

# ---------------------------------------------------------------- GPU 一行
gpu_line() {
    local out name util mu mt temp pw fan
    if ! command -v nvidia-smi >/dev/null 2>&1; then
        printf '%sGPU: nvidia-smi not found%s' "$Y" "$R"; return
    fi
    out=$(timeout 4 nvidia-smi --query-gpu=name,utilization.gpu,memory.used,memory.total,temperature.gpu,power.draw,fan.speed \
          --format=csv,noheader,nounits 2>/dev/null | head -1)
    if [ -z "$out" ]; then printf '%sGPU: query failed%s' "$RD" "$R"; return; fi
    IFS=',' read -r name util mu mt temp pw fan <<<"$out"
    name=$(trim "$name"); util=$(trim "$util"); mu=$(trim "$mu"); mt=$(trim "$mt")
    temp=$(trim "$temp"); pw=$(trim "$pw"); fan=$(trim "$fan")
    printf '%s%s%s  util %s%s%%%s  VRAM %s%s/%s MiB%s  %s%sC%s  %sW  fan %s%%' \
        "$B" "$name" "$R" "$G" "$util" "$R" "$B" "$mu" "$mt" "$R" "$Y" "$temp" "$R" "$pw" "$fan"
}

# -------------------------------------------------------------------- 主循环
while :; do
    # ---- 每轮重读配置（可在面板运行中改 /etc/sysmon.conf）----
    PORTS="$PORTS_DEFAULT"; UNITS="$UNITS_DEFAULT"; TITLE="$TITLE_DEFAULT"
    REFRESH="$REFRESH_DEFAULT"
    [ -r /etc/sysmon.conf ] && . /etc/sysmon.conf
    REFRESH="${SYSMON_REFRESH:-$REFRESH}"
    # 面板显示时区（GPU 机系统时区是 Etc/UTC；只改面板显示，不动系统设置）
    if [ -n "${PANEL_TZ:-}" ] && [ -f "/usr/share/zoneinfo/${PANEL_TZ}" ]; then
        export TZ="$PANEL_TZ"
    fi

    W=$(tput cols 2>/dev/null || echo 120)
    now=$(date '+%F %H:%M:%S')
    host=$(hostname)
    ip=$(hostname -I 2>/dev/null | awk '{print $1}')
    up=$(uptime -p 2>/dev/null | sed 's/^up //')
    read -r l1 l5 l15 _ < /proc/loadavg
    mem=$(free -m | awk 'NR==2{printf "%.1f/%.1f GiB (%d%%)", $3/1024, $2/1024, $3*100/$2}')
    disk=$(df -h / | awk 'NR==2{printf "%s used, %s free", $5, $4}')

    svc=""
    for item in $PORTS; do
        label="${item%%:*}"; port="${item##*:}"
        if port_up "$port"; then
            svc+=" ${G}*${R}${label}:${port}"
        else
            svc+=" ${RD}x${R}${D}${label}:${port}${R}"
        fi
    done

    units_active=""
    for u in $UNITS; do
        [ "$(systemctl is-active "$u" 2>/dev/null)" = "active" ] && units_active+=" ${G}${u}${R}"
    done
    [ -z "$units_active" ] && units_active=" ${D}none active${R}"

    printf '\033[H'
    hdr="  ${host}  ${ip}"
    pad=$(( W - ${#TITLE} - ${#hdr} - ${#now} - 2 ))
    [ "$pad" -lt 2 ] && pad=2
    printf '%s%s%s%s%s%s%*s%s\033[K\n' "$B" "$TITLE" "$R" "$C" "$hdr" "$R" "$pad" "$now" "$R"
    printf '%s%s%s\033[K\n' "$D" "$(printf '=%.0s' $(seq 1 $((W-1))))" "$R"
    printf '%sup %s%s  |  load %s%s %s %s%s  |  mem %s%s%s  |  disk / %s%s%s\033[K\n' \
        "$D" "$up" "$R" "$B" "$l1" "$l5" "$l15" "$R" "$M" "$mem" "$R" "$M" "$disk" "$R"
    printf 'GPU  %s\033[K\n' "$(gpu_line)"
    printf 'SVC %s\033[K\n' "$svc"
    printf 'UNIT%s\033[K\n' "$units_active"
    if [ "$W" -ge 100 ]; then
        printf '%skeys  Ctrl-b n = GPU(nvtop)   Ctrl-b d = detach to shell   Ctrl-b o = switch pane   q = quit btop%s\033[K\n' "$D" "$R"
    else
        printf '%skeys Ctrl-b n:GPU  Ctrl-b d:detach%s\033[K\n' "$D" "$R"
    fi
    printf '\033[J'

    sleep "$REFRESH"
done
