#!/usr/bin/env bash
#
# SLIKZ SYS·PERF PRO v5.1 EN
# Linux/VPS diagnostics with CPU, memory, storage and network benchmarks.
# Includes cgroup/VPS limit detection, measured performance insights, scoring and optional price context.
# Runs on modern Linux systems; dependency installation supports apt, dnf/yum, pacman, zypper and apk.
#
# Examples:
#   chmod +x slikz-sysperf-pro-v5.1-EN.sh
#   ./slikz-sysperf-pro-v5.1-EN.sh --quick
#   sudo ./slikz-sysperf-pro-v5.1-EN.sh --full --yes --install-deps
#   ./slikz-sysperf-pro-v5.1-EN.sh --full --yes --price 19.99
#   ./slikz-sysperf-pro-v5.1-EN.sh --disk-path /storage
#

set -Eeuo pipefail
# Keep machine-readable number formatting while allowing correct UTF-8 terminal widths.
if locale -a 2>/dev/null | grep -qiE '^(C\.UTF-8|C\.utf8)$'; then
  export LC_ALL=C.UTF-8
else
  export LC_ALL=C
fi

VERSION="5.1.0-PRO-EN"
MODE="full"
RUN_NETWORK=1
RUN_BENCHMARKS=1
AUTO_YES=0
INSTALL_DEPS=0
DISK_PATH="${PWD}"
CPU_SAMPLE_SECONDS="1"
BENCH_RUNTIME=10
BENCH_SIZE="1G"
TOP_COUNT=7
PRICE_EUR=""
RUN_STARTED_AT=$(date +%s)
PHASE_CURRENT=0
PHASE_TOTAL=11

# Runtime state
TEMP_FILES=()
MISSING_PACKAGES=()
FIO_SEQ_READ="-"
FIO_SEQ_WRITE="-"
FIO_RAND_READ="-"
FIO_RAND_WRITE="-"
SYSBENCH_SINGLE="-"
SYSBENCH_MULTI="-"
SYSBENCH_MEMORY="-"
NET_CF_SPEED="-"
NET_HETZNER_SPEED="-"
NET_CF_UPLOAD="-"
NET_PING_AVG="-"
STORAGE_TOTAL="-"
STORAGE_USED="-"
STORAGE_FREE="-"
STORAGE_USE_PCT="-"
STORAGE_USE_PCT_RAW=0

# Raw values for automatic analysis / scoring
FIO_SEQ_READ_BPS=0
FIO_SEQ_WRITE_BPS=0
FIO_RAND_READ_IOPS_RAW=0
FIO_RAND_WRITE_IOPS_RAW=0
FIO_SEQ_READ_LAT_MS=0
FIO_SEQ_WRITE_LAT_MS=0
FIO_RAND_READ_LAT_MS=0
FIO_RAND_WRITE_LAT_MS=0
SYSBENCH_SINGLE_RAW=0
SYSBENCH_MULTI_RAW=0
SYSBENCH_RATIO_RAW=0
SYSBENCH_MEMORY_RAW=0
NET_CF_SPEED_BPS=0
NET_HETZNER_SPEED_BPS=0
NET_CF_UPLOAD_BPS=0
NET_PING_AVG_RAW=0
PING_FRANKFURT_MS=0
PING_NEWYORK_MS=0
PING_SINGAPORE_MS=0
CPU_THREADS_RAW=0
CPU_THREADS_VISIBLE_RAW=0
CPU_THREADS_AVAILABLE_RAW=0
CPU_MODEL_RAW=""
RAM_TOTAL_BYTES_RAW=0
DISK_TOTAL_BYTES_RAW=0
MEM_USED_PCT_RAW=0
SWAP_TOTAL_BYTES_RAW=0
MEM_PSI_RAW=0
IO_PSI_RAW=0
VIRT_TYPE_RAW=""
SCORE_CPU="-"
SCORE_RAM="-"
SCORE_DISK="-"
SCORE_NET="-"
SCORE_TOTAL="-"

usage() {
  cat <<EOF
SLIKZ SYS·PERF PRO  v${VERSION}

USAGE
  $0 [OPTIONS]

MODES
  --quick                  Fast scan with lighter benchmarks
  --full                   Full analysis (default)

OPTIONS
  --no-benchmark           System diagnostics only; skip load tests
  --no-network             Skip public IP, latency and bandwidth checks
  --disk-path PATH         Filesystem path used for the storage benchmark
  --install-deps           Install missing runtime and benchmark dependencies
  --price EUR              Monthly price, e.g. 19.99, for resource-cost context
  --width N                Optimize output for 42–220 terminal columns
  --no-color               Disable ANSI colors
  --yes, -y                Run benchmarks without an interactive prompt
  --version                Print the version and exit
  --help, -h               Show this help

EXAMPLES
  $0 --quick
  sudo $0 --full --yes --install-deps
  $0 --full --yes --price 19.99
  $0 --width 52 --no-color --no-benchmark
  $0 --disk-path /mnt/storage --no-network
EOF
}


while (($#)); do
  case "$1" in
    --quick)
      MODE="quick"
      BENCH_RUNTIME=5
      BENCH_SIZE="256M"
      TOP_COUNT=5
      ;;
    --full)
      MODE="full"
      ;;
    --no-benchmark)
      RUN_BENCHMARKS=0
      ;;
    --no-network)
      RUN_NETWORK=0
      ;;
    --disk-path)
      [[ $# -ge 2 ]] || { echo "Missing value for --disk-path" >&2; exit 2; }
      DISK_PATH="$2"
      shift
      ;;
    --install-deps)
      INSTALL_DEPS=1
      ;;
    --price)
      [[ $# -ge 2 ]] || { echo "Missing value for --price" >&2; exit 2; }
      PRICE_EUR="${2/,/.}"
      if ! awk -v p="$PRICE_EUR" 'BEGIN{exit !(p ~ /^[0-9]+([.][0-9]+)?$/ && p > 0)}'; then
        echo "Invalid price: $2" >&2
        exit 2
      fi
      shift
      ;;
    --width)
      [[ $# -ge 2 ]] || { echo "Missing value for --width" >&2; exit 2; }
      [[ "$2" =~ ^[0-9]+$ ]] || { echo "Invalid width: $2" >&2; exit 2; }
      if ((10#$2 < 42 || 10#$2 > 220)); then echo "--width must be between 42 and 220" >&2; exit 2; fi
      SLIKZ_WIDTH="$2"
      shift
      ;;
    --no-color)
      NO_COLOR=1
      ;;
    --yes|-y)
      AUTO_YES=1
      ;;
    --version)
      printf '%s\n' "$VERSION"
      exit 0
      ;;
    --help|-h)
      usage
      exit 0
      ;;
    *)
      echo "Unknown option: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
  shift
done


# ---------- Terminal / visual helpers ----------
# v5 visual language: adaptive SYS·PERF dashboard for narrow mobile SSH and wide desktop terminals.
if [[ -t 1 && -z "${NO_COLOR:-}" ]]; then
  ESC=$'\033'
  RESET="${ESC}[0m"
  BOLD="${ESC}[1m"
  DIM="${ESC}[2m"
  RED="${ESC}[38;5;203m"
  GREEN="${ESC}[38;5;84m"
  YELLOW="${ESC}[38;5;220m"
  ORANGE="${ESC}[38;5;208m"
  BLUE="${ESC}[38;5;75m"
  MAGENTA="${ESC}[38;5;205m"
  CYAN="${ESC}[38;5;81m"
  PURPLE="${ESC}[38;5;141m"
  PINK="${ESC}[38;5;213m"
  LIME="${ESC}[38;5;118m"
  SKY="${ESC}[38;5;117m"
  SLATE="${ESC}[38;5;245m"
  MUTED="${ESC}[38;5;242m"
  BORDER="${ESC}[38;5;60m"
  WHITE="${ESC}[97m"
  BG_PURPLE="${ESC}[48;5;60m"
  BG_CYAN="${ESC}[48;5;24m"
  BG_GREEN="${ESC}[48;5;22m"
  BG_RED="${ESC}[48;5;88m"
else
  RESET="" BOLD="" DIM="" RED="" GREEN="" YELLOW="" ORANGE="" BLUE="" MAGENTA="" CYAN="" PURPLE="" PINK="" LIME="" SKY="" SLATE="" MUTED="" BORDER="" WHITE="" BG_PURPLE="" BG_CYAN="" BG_GREEN="" BG_RED=""
fi

term_width() {
  local width=120
  if [[ "${SLIKZ_WIDTH:-}" =~ ^[0-9]+$ ]]; then
    width="$SLIKZ_WIDTH"
  elif command -v tput >/dev/null 2>&1 && [[ -t 1 ]]; then
    width=$(tput cols 2>/dev/null || echo 120)
  elif [[ "${COLUMNS:-}" =~ ^[0-9]+$ ]]; then
    width="$COLUMNS"
  fi
  ((width < 42)) && width=42
  ((width > 220)) && width=220
  printf '%s' "$width"
}

TERM_WIDTH=$(term_width)
SECTION_INDEX=0

layout_mode() {
  if ((TERM_WIDTH < 72)); then printf 'compact'
  elif ((TERM_WIDTH < 112)); then printf 'standard'
  else printf 'wide'
  fi
}

LAYOUT_MODE=$(layout_mode)

declare -a STAT_VALUES=()

repeat_char() {
  local char="$1" count="$2" out=""
  ((count < 0)) && count=0
  printf -v out '%*s' "$count" ''
  printf '%s' "${out// /$char}"
}

print_cell() {
  local text="${1:-}" width="${2:-1}" pad
  ((width < 1)) && width=1
  if ((${#text} > width)); then
    if ((width >= 2)); then text="${text:0:$((width-1))}…"
    else text="${text:0:width}"
    fi
  fi
  printf '%s' "$text"
  pad=$((width - ${#text}))
  ((pad > 0)) && printf '%*s' "$pad" ''
  return 0
}

hr() {
  printf '%b%s%b\n' "$BORDER" "$(repeat_char '─' "$TERM_WIDTH")" "$RESET"
}

badge() {
  local text="$1" color="${2:-$CYAN}" bg="${3:-}"
  printf '%b%b %b%s%b %b' "$bg" "$color$BOLD" "$WHITE" "$text" "$RESET" "$RESET"
}

phase() {
  local label="$1" pct barw filled
  PHASE_CURRENT=$((PHASE_CURRENT + 1))
  pct=$((PHASE_CURRENT * 100 / PHASE_TOTAL))
  if [[ "$LAYOUT_MODE" == "compact" ]]; then
    barw=$((TERM_WIDTH - 14)); ((barw < 18)) && barw=18
    filled=$((pct * barw / 100))
    printf '\n  %b%02d/%02d%b  %b%s%b  %b%3d%%%b\n' "$MUTED" "$PHASE_CURRENT" "$PHASE_TOTAL" "$RESET" "$WHITE$BOLD" "$label" "$RESET" "$LIME$BOLD" "$pct" "$RESET"
    printf '  %b[%b%b%s%b%b%s%b%b]%b\n' "$BORDER" "$RESET" "$PURPLE" "$(repeat_char '■' "$filled")" "$RESET" "$MUTED" "$(repeat_char '·' "$((barw-filled))")" "$RESET" "$BORDER" "$RESET"
  else
    barw=$((TERM_WIDTH - 52)); ((barw < 12)) && barw=12; ((barw > 80)) && barw=80
    printf '\n  %b%02d/%02d%b  %b' "$MUTED" "$PHASE_CURRENT" "$PHASE_TOTAL" "$RESET" "$WHITE$BOLD"
    print_cell "$label" 28
    printf '%b  %b' "$RESET" "$BORDER"
    printf '%s' "$(repeat_char '─' "$barw")"
    printf '%b  %b%3d%%%b\n' "$RESET" "$LIME$BOLD" "$pct" "$RESET"
  fi
}

metric_card() {
  local label="$1" value="$2" color="${3:-$CYAN}" inner fill
  inner=$((TERM_WIDTH - 4))
  fill=$((inner - ${#label} - 5)); ((fill < 3)) && fill=3
  printf '  %b╭─%b %b%s%b %b%s╮%b\n' "$BORDER" "$RESET" "$color$BOLD" "$label" "$RESET" "$BORDER" "$(repeat_char '─' "$fill")" "$RESET"
  printf '  %b│%b %b%s%b\n' "$BORDER" "$RESET" "$WHITE$BOLD" "$value" "$RESET"
  printf '  %b╰%s╯%b\n' "$BORDER" "$(repeat_char '─' "$inner")" "$RESET"
}

section() {
  local title="$1" icon="◆" label="$1" accent="$PURPLE" rest
  SECTION_INDEX=$((SECTION_INDEX + 1))
  case "$title" in
    'SYSTEM') icon='▣'; label='SYSTEM'; accent="$SKY" ;;
    'VPS LIMITS') icon='◇'; label='VPS'; accent="$PURPLE" ;;
    'CPU') icon='◉'; label='CPU'; accent="$CYAN" ;;
    'TOP PROCESSES') icon='▲'; label='PROCESSES'; accent="$MAGENTA" ;;
    'MEMORY') icon='▤'; label='RAM'; accent="$GREEN" ;;
    'STORAGE') icon='▰'; label='STORAGE'; accent="$YELLOW" ;;
    'DISK BENCH') icon='◆'; label='DISK BENCH'; accent="$ORANGE" ;;
    'CPU BENCH') icon='◈'; label='CPU BENCH'; accent="$CYAN" ;;
    'NETWORK') icon='◎'; label='NETWORK'; accent="$BLUE" ;;
    'LIVE I/O') icon='↕'; label='I/O'; accent="$YELLOW" ;;
    'INSIGHTS') icon='✦'; label='INSIGHTS'; accent="$PINK" ;;
    'RESULTS') icon='✓'; label='RESULTS'; accent="$LIME" ;;
    'DEPENDENCIES') icon='+'; label='SETUP'; accent="$YELLOW" ;;
  esac
  rest=$((TERM_WIDTH - ${#label} - 11)); ((rest < 3)) && rest=3
  printf '\n  %b%s%b %b%s%b  %b%s%b\n' "$accent$BOLD" "$icon" "$RESET" "$WHITE$BOLD" "$label" "$RESET" "$BORDER" "$(repeat_char '─' "$rest")" "$RESET"
}

subsection() {
  local label="$1"
  printf '  %b%s%b\n' "$MUTED$BOLD" "$label" "$RESET"
}

kv() {
  local key="$1" value="${2:--}" color="${3:-$WHITE}" wrap line
  if [[ "$LAYOUT_MODE" == "compact" ]]; then
    wrap=$((TERM_WIDTH - 6)); ((wrap < 28)) && wrap=28
    printf '  %b%s%b\n' "$MUTED" "$key" "$RESET"
    while IFS= read -r line; do printf '    %b%s%b\n' "$color$BOLD" "$line" "$RESET"; done < <(printf '%s\n' "$value" | fold -s -w "$wrap")
  elif ((${#value} > TERM_WIDTH - 22)); then
    wrap=$((TERM_WIDTH - 6)); ((wrap < 40)) && wrap=40
    printf '  %b%s%b\n' "$MUTED" "$key" "$RESET"
    while IFS= read -r line; do printf '    %b%s%b\n' "$color$BOLD" "$line" "$RESET"; done < <(printf '%s\n' "$value" | fold -s -w "$wrap")
  else
    printf '  %b%-17s%b %b%s%b\n' "$MUTED" "$key" "$RESET" "$color$BOLD" "$value" "$RESET"
  fi
}

wide_value() { kv "$@"; }

grid2() {
  local k1="$1" v1="${2:--}" k2="$3" v2="${4:--}"
  if ((TERM_WIDTH < 86)); then
    kv "$k1" "$v1"
    kv "$k2" "$v2"
    return
  fi
  local gap=5 col keyw valw
  keyw=15
  col=$(((TERM_WIDTH - 4 - gap) / 2))
  valw=$((col - keyw - 1)); ((valw < 10)) && valw=10
  printf '  %b' "$MUTED"; print_cell "$k1" "$keyw"; printf '%b ' "$RESET"
  printf '%b' "$WHITE$BOLD"; print_cell "$v1" "$valw"; printf '%b%*s' "$RESET" "$gap" ''
  printf '%b' "$MUTED"; print_cell "$k2" "$keyw"; printf '%b ' "$RESET"
  printf '%b' "$WHITE$BOLD"; print_cell "$v2" "$valw"; printf '%b\n' "$RESET"
}

stat_grid() {
  local requested="$1"; shift
  local n="$requested" maxcols gap usable col i start wrap line
  if ((TERM_WIDTH < 72)); then maxcols=1
  elif ((TERM_WIDTH < 112)); then maxcols=2
  else maxcols=4
  fi
  ((n < maxcols)) && maxcols=$n
  gap=3
  usable=$((TERM_WIDTH - 4 - gap * (maxcols - 1)))
  col=$((usable / maxcols)); ((col < 16)) && col=16
  local -a labels=() values=()
  for ((i=0; i<n; i++)); do
    labels[$i]="${1:-}"; values[$i]="${2:--}"; shift 2 || true
  done
  if ((maxcols == 1)); then
    wrap=$((TERM_WIDTH - 4)); ((wrap < 28)) && wrap=28
    for ((i=0; i<n; i++)); do
      printf '  %b%s%b\n' "$MUTED" "${labels[$i]}" "$RESET"
      while IFS= read -r line; do printf '  %b%s%b\n' "$WHITE$BOLD" "$line" "$RESET"; done < <(printf '%s\n' "${values[$i]}" | fold -s -w "$wrap")
      ((i+1<n)) && printf '\n'
    done
    return 0
  fi
  for ((start=0; start<n; start+=maxcols)); do
    printf '  '
    for ((i=0; i<maxcols && start+i<n; i++)); do
      printf '%b' "$MUTED"; print_cell "${labels[$((start+i))]}" "$col"; printf '%b' "$RESET"
      if ((i+1<maxcols && start+i+1<n)); then printf '%*s' "$gap" ''; fi
    done
    printf '\n  '
    for ((i=0; i<maxcols && start+i<n; i++)); do
      printf '%b' "$WHITE$BOLD"; print_cell "${values[$((start+i))]}" "$col"; printf '%b' "$RESET"
      if ((i+1<maxcols && start+i+1<n)); then printf '%*s' "$gap" ''; fi
    done
    printf '\n'
    if ((start + maxcols < n)); then printf '\n'; fi
  done
  return 0
}

bar() {
  local percent width color="${3:-}"
  percent=$(clamp_percent "${1:-0}")
  width="${2:-24}"
  local filled empty
  filled=$((percent * width / 100))
  empty=$((width - filled))
  if [[ -z "$color" ]]; then
    color="$GREEN"
    ((percent >= 65)) && color="$YELLOW"
    ((percent >= 85)) && color="$RED"
  fi
  printf '%b[%b%b%s%b%b%s%b%b]%b' "$BORDER" "$RESET" "$color" "$(repeat_char '■' "$filled")" "$RESET" "$MUTED" "$(repeat_char '·' "$empty")" "$RESET" "$BORDER" "$RESET"
}

wide_bar() {
  local label="$1" pct="$2" suffix="${3:-}" color="${4:-}" bw inline_need wrap line
  [[ -n "$color" ]] || case "$label" in
    RAM*) color="$GREEN" ;; SWAP*) color="$PURPLE" ;; TESTPFAD*|DISK*) color="$YELLOW" ;; *) color="$CYAN" ;; esac
  if [[ "$LAYOUT_MODE" == "compact" ]]; then
    bw=$((TERM_WIDTH - 10)); ((bw < 20)) && bw=20
    printf '  %b%s%b  %b%5.1f%%%b\n  ' "$color$BOLD" "$label" "$RESET" "$WHITE$BOLD" "$pct" "$RESET"
    bar "$pct" "$bw" "$color"
    printf '\n'
    wrap=$((TERM_WIDTH - 4)); ((wrap < 28)) && wrap=28
    while IFS= read -r line; do printf '  %b%s%b\n' "$MUTED" "$line" "$RESET"; done < <(printf '%s\n' "$suffix" | fold -s -w "$wrap")
  else
    inline_need=$((TERM_WIDTH - 28 - ${#suffix}))
    if ((inline_need >= 18)); then
      bw="$inline_need"; ((bw > 100)) && bw=100
      printf '  %b│%b %b%-12s%b ' "$BORDER" "$RESET" "$color$BOLD" "$label" "$RESET"
      bar "$pct" "$bw" "$color"
      printf ' %b%5.1f%%%b  %b%s%b\n' "$WHITE$BOLD" "$pct" "$RESET" "$MUTED" "$suffix" "$RESET"
    else
      bw=$((TERM_WIDTH - 28)); ((bw < 24)) && bw=24; ((bw > 100)) && bw=100
      printf '  %b│%b %b%-12s%b ' "$BORDER" "$RESET" "$color$BOLD" "$label" "$RESET"
      bar "$pct" "$bw" "$color"
      printf ' %b%5.1f%%%b\n' "$WHITE$BOLD" "$pct" "$RESET"
      wrap=$((TERM_WIDTH - 4));
      while IFS= read -r line; do printf '  %b%s%b\n' "$MUTED" "$line" "$RESET"; done < <(printf '%s\n' "$suffix" | fold -s -w "$wrap")
    fi
  fi
}

cpu_mix_bar() {
  local user="${1:-0}" sys="${2:-0}" io="${3:-0}" steal="${4:-0}" width
  if [[ "$LAYOUT_MODE" == "compact" ]]; then width=$((TERM_WIDTH - 6)); else width=$((TERM_WIDTH - 48)); fi
  ((width<24))&&width=24; ((width>132))&&width=132
  local u s i st busy idle
  u=$(awk -v p="$user" -v w="$width" 'BEGIN{printf "%.0f",p*w/100}')
  s=$(awk -v p="$sys" -v w="$width" 'BEGIN{printf "%.0f",p*w/100}')
  i=$(awk -v p="$io" -v w="$width" 'BEGIN{printf "%.0f",p*w/100}')
  st=$(awk -v p="$steal" -v w="$width" 'BEGIN{printf "%.0f",p*w/100}')
  busy=$((u+s+i+st)); ((busy>width))&&busy=$width
  idle=$((width-busy))
  printf '  %b[%b' "$BORDER" "$RESET"
  printf '%b%s%b' "$GREEN" "$(repeat_char '■' "$u")" "$RESET"
  printf '%b%s%b' "$MAGENTA" "$(repeat_char '■' "$s")" "$RESET"
  printf '%b%s%b' "$YELLOW" "$(repeat_char '■' "$i")" "$RESET"
  printf '%b%s%b' "$RED" "$(repeat_char '■' "$st")" "$RESET"
  printf '%b%s%b%b]%b\n' "$MUTED" "$(repeat_char '·' "$idle")" "$RESET" "$BORDER" "$RESET"
  printf '  %bU%b %.1f%%  %bS%b %.1f%%  %bIO%b %.1f%%  %bSTL%b %.1f%%\n' "$GREEN$BOLD" "$RESET" "$user" "$MAGENTA$BOLD" "$RESET" "$sys" "$YELLOW$BOLD" "$RESET" "$io" "$RED$BOLD" "$RESET" "$steal"
}

score_meter() {
  local label="$1" score="$2" width=18 color="$CYAN"
  if [[ "$score" == "-" || ! "$score" =~ ^[0-9]+$ ]]; then
    printf '%b%-12s%b %b[not measured]%b' "$CYAN" "$label" "$RESET" "$MUTED" "$RESET"
    return
  fi
  ((score>=85)) && color="$LIME" || { ((score>=70)) && color="$GREEN" || { ((score>=50)) && color="$YELLOW" || color="$RED"; }; }
  printf '%b%-12s%b ' "$CYAN" "$label" "$RESET"
  bar "$score" "$width" "$color"
  printf ' %b%3d%b' "$color$BOLD" "$score" "$RESET"
}

status_line() {
  local icon="$1" color="$2"; shift 2
  local text="$*" wrap=$((TERM_WIDTH - 7)) first=1 line
  ((wrap < 28)) && wrap=28
  if ((${#text} + 4 <= TERM_WIDTH)); then
    printf '  %b%s%b %s\n' "$color$BOLD" "$icon" "$RESET" "$text"
    return 0
  fi
  while IFS= read -r line; do
    if ((first)); then
      printf '  %b%s%b %s\n' "$color$BOLD" "$icon" "$RESET" "$line"
      first=0
    else
      printf '    %s\n' "$line"
    fi
  done < <(printf '%s\n' "$text" | fold -s -w "$wrap")
}

ok()   { status_line '✓' "$LIME" "$*"; }
warn() { status_line '!' "$YELLOW" "$*"; }
fail() { status_line '×' "$RED" "$*"; }
info() { status_line '•' "$SKY" "$*"; }

clamp_percent() {
  awk -v n="${1:-0}" 'BEGIN { if (n < 0) n=0; if (n > 100) n=100; printf "%.0f", n }'
}

human_bytes() {
  local bytes="${1:-0}"
  awk -v b="$bytes" 'BEGIN {
    if (b == "" || b !~ /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/) {printf "%s B", b; exit}
    if (b < 0) b=0;
    split("B KiB MiB GiB TiB PiB",u," "); i=1;
    while (b>=1024 && i<6) {b/=1024;i++}
    if (i==1) printf "%.0f %s", b, u[i]; else printf "%.1f %s", b, u[i]
  }'
}


human_rate() {
  local bytes="${1:-0}"
  printf '%s/s' "$(human_bytes "$bytes")"
}

format_number() {
  local number="${1:-0}"
  awk -v n="$number" 'BEGIN {
    s=sprintf("%.0f",n); out="";
    while (length(s)>3) {
      out="." substr(s,length(s)-2,3) out;
      s=substr(s,1,length(s)-3)
    }
    print s out
  }'
}

network_rate() {
  local bytes="${1:-0}"
  awk -v b="$bytes" 'BEGIN {
    if (b < 0) b=0;
    printf "%.1f Mbit/s · %.1f MiB/s", (b*8)/1000000, b/1048576
  }'
}

format_seconds() {
  local total="${1:-0}" days hours mins secs
  total=${total%.*}
  days=$((total / 86400))
  hours=$(((total % 86400) / 3600))
  mins=$(((total % 3600) / 60))
  secs=$((total % 60))
  if ((days > 0)); then
    printf '%dT %02dh %02dm' "$days" "$hours" "$mins"
  elif ((hours > 0)); then
    printf '%dh %02dm %02ds' "$hours" "$mins" "$secs"
  else
    printf '%dm %02ds' "$mins" "$secs"
  fi
}

format_uptime() {
  local total="${1:-0}" days hours mins
  total=${total%.*}
  days=$((total / 86400))
  hours=$(((total % 86400) / 3600))
  mins=$(((total % 3600) / 60))
  if [[ "$LAYOUT_MODE" == "compact" ]]; then
    if ((days > 0)); then printf '%dd %02dh' "$days" "$hours"
    elif ((hours > 0)); then printf '%dh %02dm' "$hours" "$mins"
    else printf '%dm' "$mins"; fi
  else
    if ((days > 0)); then printf '%d days · %02d:%02d h' "$days" "$hours" "$mins"
    elif ((hours > 0)); then printf '%d:%02d h' "$hours" "$mins"
    else printf '%d min' "$mins"; fi
  fi
}

os_short_name() {
  if [[ -r /etc/os-release ]]; then
    local name version
    name=$(awk -F= '$1=="NAME" {gsub(/^"|"$/,"",$2); print $2; exit}' /etc/os-release)
    version=$(awk -F= '$1=="VERSION_ID" {gsub(/^"|"$/,"",$2); print $2; exit}' /etc/os-release)
    case "$name" in
      "Debian GNU/Linux") name="Debian" ;;
      "Ubuntu") name="Ubuntu" ;;
    esac
    printf '%s%s' "$name" "${version:+ $version}"
  else
    uname -s
  fi
}

cpu_short_name() {
  local model="${1:-}"
  model=${model#AMD }
  model=${model#Intel(R) }
  model=${model// CPU/}
  model=$(sed -E 's/[[:space:]]+[0-9]+-Core Processor$//; s/[[:space:]]+Processor$//; s/[[:space:]]+@.*$//' <<<"$model")
  printf '%s' "$model"
}

cpu_visible_threads() {
  local n
  n=$(grep -c '^processor[[:space:]]*:' /proc/cpuinfo 2>/dev/null || true)
  [[ "$n" =~ ^[0-9]+$ && "$n" -gt 0 ]] && printf '%s' "$n" || nproc --all 2>/dev/null || nproc 2>/dev/null || printf '?'
}

cpu_available_threads() {
  nproc 2>/dev/null || cpu_visible_threads
}

cpu_allowed_list() {
  awk -F: '/^Cpus_allowed_list:/ {gsub(/[[:space:]]/,"",$2); print $2; exit}' /proc/self/status 2>/dev/null || true
}

cpu_allowed_keys() {
  local list
  list=$(cpu_allowed_list)
  [[ -n "$list" ]] || return 0
  awk -v list="$list" 'BEGIN {
    n=split(list,a,",");
    for(i=1;i<=n;i++) {
      if(a[i] ~ /-/) { split(a[i],r,"-"); for(j=r[1];j<=r[2];j++) print "cpu" j }
      else if(a[i] ~ /^[0-9]+$/) print "cpu" a[i]
    }
  }'
}

percent_of() {
  local used="${1:-0}" total="${2:-0}"
  awk -v u="$used" -v t="$total" 'BEGIN { if (t <= 0) print 0; else printf "%.1f", (u/t)*100 }'
}

safe_cmd() {
  command -v "$1" >/dev/null 2>&1
}


get_fio_bin() {
  local candidate
  for candidate in "$(command -v fio 2>/dev/null || true)" /usr/bin/fio /usr/local/bin/fio; do
    [[ -n "$candidate" && -x "$candidate" ]] || continue
    if "$candidate" --version 2>/dev/null | head -n1 | grep -Eq '^fio-[0-9]'; then
      printf '%s' "$candidate"
      return 0
    fi
  done
  return 1
}


is_number() {
  awk -v n="${1:-}" 'BEGIN{exit !(n ~ /^[-+]?[0-9]+([.][0-9]+)?$/)}'
}

link_speed_label() {
  local speed="${1:-}"
  if [[ "$speed" =~ ^[0-9]+$ ]] && ((speed > 0)); then
    printf '%s Mbit/s' "$speed"
  else
    printf 'virtual / not reported'
  fi
}

score_label() {
  local score="${1:--}"
  if [[ "$score" == "-" ]]; then printf 'not rated'; return; fi
  if ((score >= 90)); then printf 'Excellent'
  elif ((score >= 80)); then printf 'Very good'
  elif ((score >= 70)); then printf 'Good'
  elif ((score >= 55)); then printf 'Solid'
  elif ((score >= 40)); then printf 'Average'
  else printf 'Weak'
  fi
}

insight() {
  local level="$1" title="$2" text="$3" icon color wrap line prefix_len
  case "$level" in
    good) icon='✓'; color="$GREEN" ;;
    warn) icon='!'; color="$YELLOW" ;;
    bad)  icon='×'; color="$RED" ;;
    *)    icon='•'; color="$CYAN" ;;
  esac
  prefix_len=$((4 + ${#title} + 1))
  if ((prefix_len + ${#text} <= TERM_WIDTH)); then
    printf '  %b%s%b %b%s%b %s\n' "$color$BOLD" "$icon" "$RESET" "$BOLD" "$title" "$RESET" "$text"
    return 0
  fi
  wrap=$((TERM_WIDTH - 7)); ((wrap < 30)) && wrap=30
  printf '  %b%s%b %b%s%b\n' "$color$BOLD" "$icon" "$RESET" "$BOLD" "$title" "$RESET"
  while IFS= read -r line; do printf '    %s\n' "$line"; done < <(printf '%s\n' "$text" | fold -s -w "$wrap")
}

rating_bar() {
  local label="$1" score="$2"
  if [[ "$score" == "-" ]]; then
    printf '  %-16s  %b%-14s%b  %s\n' "$label" "$DIM" 'not rated' "$RESET" 'Benchmark missing'
    return
  fi
  printf '  %-16s  ' "$label"
  bar "$score" 22
  printf '  %3d/100  %s\n' "$score" "$(score_label "$score")"
}

cleanup() {
  local file
  for file in "${TEMP_FILES[@]:-}"; do
    [[ -n "$file" && -e "$file" ]] && rm -f -- "$file" || true
  done
}
trap cleanup EXIT INT TERM

# ---------- Dependency handling ----------
package_manager() {
  local pm
  for pm in apt-get dnf yum pacman zypper apk; do
    command -v "$pm" >/dev/null 2>&1 && { printf '%s' "$pm"; return 0; }
  done
  return 1
}

package_for_command() {
  local cmd="$1" pm="$2"
  case "$pm:$cmd" in
    apt-get:awk) echo gawk ;; apt-get:sed) echo sed ;; apt-get:grep) echo grep ;;
    apt-get:fold|apt-get:df|apt-get:head|apt-get:tail|apt-get:mktemp|apt-get:nproc|apt-get:hostname|apt-get:xargs) echo coreutils ;;
    apt-get:lscpu|apt-get:lsblk|apt-get:findmnt) echo util-linux ;;
    apt-get:free|apt-get:ps) echo procps ;; apt-get:ip) echo iproute2 ;; apt-get:ping) echo iputils-ping ;;
    apt-get:sensors) echo lm-sensors ;; apt-get:smartctl) echo smartmontools ;; apt-get:iostat) echo sysstat ;;
    apt-get:lspci) echo pciutils ;;

    dnf:awk|yum:awk) echo gawk ;; dnf:sed|yum:sed) echo sed ;; dnf:grep|yum:grep) echo grep ;;
    dnf:fold|yum:fold|dnf:df|yum:df|dnf:head|yum:head|dnf:tail|yum:tail|dnf:mktemp|yum:mktemp|dnf:nproc|yum:nproc|dnf:hostname|yum:hostname|dnf:xargs|yum:xargs) echo coreutils ;;
    dnf:lscpu|yum:lscpu|dnf:lsblk|yum:lsblk|dnf:findmnt|yum:findmnt) echo util-linux ;;
    dnf:free|yum:free|dnf:ps|yum:ps) echo procps-ng ;; dnf:ip|yum:ip) echo iproute ;; dnf:ping|yum:ping) echo iputils ;;
    dnf:sensors|yum:sensors) echo lm_sensors ;; dnf:smartctl|yum:smartctl) echo smartmontools ;; dnf:iostat|yum:iostat) echo sysstat ;;
    dnf:lspci|yum:lspci) echo pciutils ;;

    pacman:awk) echo gawk ;; pacman:sed) echo sed ;; pacman:grep) echo grep ;;
    pacman:fold|pacman:df|pacman:head|pacman:tail|pacman:mktemp|pacman:nproc|pacman:hostname|pacman:xargs) echo coreutils ;;
    pacman:lscpu|pacman:lsblk|pacman:findmnt) echo util-linux ;; pacman:free|pacman:ps) echo procps-ng ;;
    pacman:ip) echo iproute2 ;; pacman:ping) echo iputils ;; pacman:sensors) echo lm_sensors ;;
    pacman:smartctl) echo smartmontools ;; pacman:iostat) echo sysstat ;; pacman:lspci) echo pciutils ;;

    zypper:awk) echo gawk ;; zypper:sed) echo sed ;; zypper:grep) echo grep ;;
    zypper:fold|zypper:df|zypper:head|zypper:tail|zypper:mktemp|zypper:nproc|zypper:hostname|zypper:xargs) echo coreutils ;;
    zypper:lscpu|zypper:lsblk|zypper:findmnt) echo util-linux ;; zypper:free|zypper:ps) echo procps ;;
    zypper:ip) echo iproute2 ;; zypper:ping) echo iputils ;; zypper:sensors) echo sensors ;;
    zypper:smartctl) echo smartmontools ;; zypper:iostat) echo sysstat ;; zypper:lspci) echo pciutils ;;

    apk:awk) echo gawk ;; apk:sed) echo sed ;; apk:grep) echo grep ;;
    apk:fold|apk:df|apk:head|apk:tail|apk:mktemp|apk:nproc|apk:xargs) echo coreutils ;; apk:hostname) echo hostname ;;
    apk:lscpu|apk:lsblk|apk:findmnt) echo util-linux ;; apk:free|apk:ps) echo procps ;; apk:ip) echo iproute2 ;;
    apk:ping) echo iputils ;; apk:sensors) echo lm-sensors ;; apk:smartctl) echo smartmontools ;; apk:iostat) echo sysstat ;;
    apk:lspci) echo pciutils ;;

    *:curl) echo curl ;; *:jq) echo jq ;; *:fio) echo fio ;; *:sysbench) echo sysbench ;;
    *) echo "$cmd" ;;
  esac
}

collect_missing_packages() {
  local cmd pkg pm
  MISSING_PACKAGES=()
  pm=$(package_manager 2>/dev/null || true)

  local commands=(awk sed grep fold df head tail mktemp nproc hostname xargs lscpu lsblk findmnt free ps ip sensors smartctl iostat)
  ((RUN_NETWORK)) && commands+=(curl ping jq)
  ((RUN_BENCHMARKS)) && commands+=(fio sysbench jq)

  for cmd in "${commands[@]}"; do
    if [[ "$cmd" == "fio" ]]; then
      get_fio_bin >/dev/null 2>&1 && continue
    elif safe_cmd "$cmd"; then
      continue
    fi
    pkg=$(package_for_command "$cmd" "${pm:-unknown}")
    [[ " ${MISSING_PACKAGES[*]:-} " == *" $pkg "* ]] || MISSING_PACKAGES+=("$pkg")
  done
}

install_dependencies() {
  local pm
  collect_missing_packages
  ((${#MISSING_PACKAGES[@]} == 0)) && return 0

  if ((INSTALL_DEPS == 0)); then
    section "DEPENDENCIES"
    warn "Missing packages: ${MISSING_PACKAGES[*]}"
    info "The base scan will continue; unavailable measurements are reported as 'not measured'."
    info "For a complete run: sudo $0 --full --yes --install-deps"
    return 0
  fi

  if [[ $EUID -ne 0 ]]; then
    fail "--install-deps requires root privileges. Run the command with sudo or as root."
    return 1
  fi

  pm=$(package_manager 2>/dev/null || true)
  if [[ -z "$pm" ]]; then
    fail "No supported package manager was found. Install these packages manually: ${MISSING_PACKAGES[*]}"
    return 1
  fi

  section "DEPENDENCIES"
  info "Package manager: $pm"
  info "Installing: ${MISSING_PACKAGES[*]}"
  case "$pm" in
    apt-get)
      DEBIAN_FRONTEND=noninteractive apt-get update -qq
      DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${MISSING_PACKAGES[@]}"
      ;;
    dnf) dnf install -y "${MISSING_PACKAGES[@]}" ;;
    yum) yum install -y "${MISSING_PACKAGES[@]}" ;;
    pacman) pacman -S --needed --noconfirm "${MISSING_PACKAGES[@]}" ;;
    zypper) zypper --non-interactive install --no-recommends "${MISSING_PACKAGES[@]}" ;;
    apk) apk add --no-cache "${MISSING_PACKAGES[@]}" ;;
  esac

  collect_missing_packages
  if ((${#MISSING_PACKAGES[@]} > 0)); then
    warn "Some dependencies are still unavailable: ${MISSING_PACKAGES[*]}"
    return 1
  fi
  ok "Dependencies installed"
}

# ---------- Generic system helpers ----------
os_pretty_name() {
  if [[ -r /etc/os-release ]]; then
    # shellcheck disable=SC1091
    . /etc/os-release
    printf '%s' "${PRETTY_NAME:-${NAME:-Linux}}"
  else
    uname -s
  fi
}

virtualization_type() {
  if safe_cmd systemd-detect-virt; then
    local virt
    virt=$(systemd-detect-virt 2>/dev/null || true)
    [[ -z "$virt" || "$virt" == "none" ]] && printf 'Bare metal' || printf '%s' "$virt"
  else
    printf 'Unknown'
  fi
}

get_primary_interface() {
  ip route show default 2>/dev/null | awk 'NR==1 {print $5}' || true
}

get_primary_ipv4() {
  local iface="$1"
  [[ -n "$iface" ]] || return 0
  ip -4 -o addr show dev "$iface" scope global 2>/dev/null | awk 'NR==1 {print $4}' || true
}

get_primary_ipv6() {
  local iface="$1"
  [[ -n "$iface" ]] || return 0
  ip -6 -o addr show dev "$iface" scope global 2>/dev/null | awk 'NR==1 {print $4}' || true
}

# ---------- Header ----------
print_header() {
  local host now arch mode_badge price_text inner c1 c2 c3 c4 p1 p2 p3 p4
  local virt os_short cpu_short ram_bytes ram_short model
  host=$(hostname 2>/dev/null || echo unknown)
  now=$(date '+%d.%m.%Y %H:%M')
  arch=$(uname -m)
  mode_badge="FULL"; [[ "$MODE" == "quick" ]] && mode_badge="QUICK"
  price_text=""; [[ -n "$PRICE_EUR" ]] && price_text=" · $(printf '%.2f EUR/month' "$PRICE_EUR")"
  inner=$((TERM_WIDTH-2))
  virt=$(virtualization_type)
  os_short=$(os_short_name)
  model=$(lscpu_value 'Model name')
  cpu_short=$(cpu_short_name "${model:-CPU unknown}")
  ram_bytes=$(awk '/MemTotal/ {printf "%.0f",$2*1024; exit}' /proc/meminfo 2>/dev/null || echo 0)
  ram_short=$(human_bytes "${ram_bytes:-0}")

  if [[ "$LAYOUT_MODE" == "compact" ]]; then
    c1="SLIKZ // SYS·PERF PRO"
    c2="$host · $mode_badge · $virt"
    c3="$os_short · $cpu_short · $ram_short RAM"
    c4="$now · $arch · v$VERSION$price_text"
    for v in c1 c2 c3 c4; do
      local value="${!v}"
      if ((${#value} > TERM_WIDTH-4)); then printf -v "$v" '%s…' "${value:0:$((TERM_WIDTH-5))}"; fi
    done
    p1=$((TERM_WIDTH - 4 - ${#c1})); ((p1<0))&&p1=0
    p2=$((TERM_WIDTH - 4 - ${#c2})); ((p2<0))&&p2=0
    p3=$((TERM_WIDTH - 4 - ${#c3})); ((p3<0))&&p3=0
    p4=$((TERM_WIDTH - 4 - ${#c4})); ((p4<0))&&p4=0
    printf '%b╭%s╮%b\n' "$PURPLE" "$(repeat_char '─' "$inner")" "$RESET"
    printf '%b│%b %b%s%b%*s %b│%b\n' "$PURPLE" "$RESET" "$CYAN$BOLD" "$c1" "$RESET" "$p1" '' "$PURPLE" "$RESET"
    printf '%b│%b %b%s%b%*s %b│%b\n' "$PURPLE" "$RESET" "$LIME$BOLD" "$c2" "$RESET" "$p2" '' "$PURPLE" "$RESET"
    printf '%b│%b %b%s%b%*s %b│%b\n' "$PURPLE" "$RESET" "$WHITE" "$c3" "$RESET" "$p3" '' "$PURPLE" "$RESET"
    printf '%b│%b %b%s%b%*s %b│%b\n' "$PURPLE" "$RESET" "$MUTED" "$c4" "$RESET" "$p4" '' "$PURPLE" "$RESET"
    printf '%b╰%s╯%b\n' "$PURPLE" "$(repeat_char '─' "$inner")" "$RESET"
  else
    local title='S L I K Z // SYS·PERF PRO' fill meta meta_pad
    fill=$((TERM_WIDTH - ${#title} - 5)); ((fill < 3)) && fill=3
    printf '%b╭─%b %bS L I K Z%b %b//%b %bSYS·PERF PRO%b %b%s╮%b\n' "$PURPLE" "$RESET" "$WHITE$BOLD" "$RESET" "$PINK$BOLD" "$RESET" "$CYAN$BOLD" "$RESET" "$PURPLE" "$(repeat_char '─' "$fill")" "$RESET"
    meta="$host · $mode_badge · $virt · $os_short · $cpu_short · $ram_short RAM · $now · $arch · v$VERSION$price_text"
    if ((${#meta} > TERM_WIDTH-4)); then meta="${meta:0:$((TERM_WIDTH-5))}…"; fi
    meta_pad=$((TERM_WIDTH - 4 - ${#meta})); ((meta_pad<0))&&meta_pad=0
    printf '%b│%b  %b%s%b%s%b│%b\n' "$PURPLE" "$RESET" "$WHITE$BOLD" "$meta" "$RESET" "$(repeat_char ' ' "$meta_pad")" "$PURPLE" "$RESET"
    printf '%b╰%s╯%b\n' "$PURPLE" "$(repeat_char '─' "$inner")" "$RESET"
  fi
  printf '  %bLayout%b %s · %s columns detected\n' "$MUTED" "$RESET" "${LAYOUT_MODE^^}" "$TERM_WIDTH"
}
# ---------- Overview ----------
show_system_overview() {
  section "SYSTEM"
  local uptime_s virt os kernel host arch
  uptime_s=$(awk '{print $1}' /proc/uptime 2>/dev/null || echo 0)
  virt=$(virtualization_type); VIRT_TYPE_RAW="$virt"
  os=$(os_pretty_name); kernel=$(uname -r); host=$(hostname -f 2>/dev/null || hostname); arch=$(uname -m)
  stat_grid 4 "OS" "$os" "KERNEL" "$kernel" "UPTIME" "$(format_uptime "$uptime_s")" "ARCH" "$arch"
}


cgroup_memory_limit() {
  local value=""
  if [[ -r /sys/fs/cgroup/memory.max ]]; then
    value=$(cat /sys/fs/cgroup/memory.max 2>/dev/null || true)
  elif [[ -r /sys/fs/cgroup/memory/memory.limit_in_bytes ]]; then
    value=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes 2>/dev/null || true)
  fi
  if [[ "$value" =~ ^[0-9]+$ && "$value" -lt 9223372036854771712 ]]; then
    human_bytes "$value"
  else
    printf 'no cgroup limit / host memory visible'
  fi
}

cgroup_cpu_limit() {
  local quota period visible
  visible=$(nproc 2>/dev/null || echo '?')
  if [[ -r /sys/fs/cgroup/cpu.max ]]; then
    read -r quota period < /sys/fs/cgroup/cpu.max
  elif [[ -r /sys/fs/cgroup/cpu/cpu.cfs_quota_us && -r /sys/fs/cgroup/cpu/cpu.cfs_period_us ]]; then
    quota=$(cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us 2>/dev/null || echo -1)
    period=$(cat /sys/fs/cgroup/cpu/cpu.cfs_period_us 2>/dev/null || echo 100000)
  else
    printf 'no cgroup quota detected · %s threads visible' "$visible"
    return
  fi
  if [[ "$quota" == "max" || "$quota" == "-1" ]]; then
    printf 'unlimited by cgroup · %s threads visible' "$visible"
  elif [[ "$quota" =~ ^[0-9]+$ && "$period" =~ ^[0-9]+$ && "$period" -gt 0 ]]; then
    awk -v q="$quota" -v p="$period" -v v="$visible" 'BEGIN {printf "%.2f CPU-core quota · %s threads visible",q/p,v}'
  else
    printf 'ambiguous · %s threads visible' "$visible"
  fi
}

show_effective_limits() {
  local mem_total pids_limit threads_available threads_visible memlimit cpulimit proc_short virt allowed
  mem_total=$(awk '/MemTotal/ {printf "%.0f",$2*1024; exit}' /proc/meminfo)
  RAM_TOTAL_BYTES_RAW="${mem_total:-0}"
  threads_available=$(cpu_available_threads)
  threads_visible=$(cpu_visible_threads)
  CPU_THREADS_AVAILABLE_RAW="${threads_available:-0}"
  CPU_THREADS_VISIBLE_RAW="${threads_visible:-0}"
  pids_limit=$(cat /sys/fs/cgroup/pids.max 2>/dev/null || true)
  if [[ -z "$pids_limit" || "$pids_limit" == "max" ]]; then proc_short="unlimited"
  elif [[ "$pids_limit" =~ ^[0-9]+$ ]]; then proc_short="$pids_limit"
  else proc_short="not detected"; fi
  memlimit=$(cgroup_memory_limit); cpulimit=$(cgroup_cpu_limit)
  virt=$(virtualization_type)
  allowed=$(cpu_allowed_list); [[ -z "$allowed" ]] && allowed="alle"

  stat_grid 4 "vCPU" "$threads_available available · $threads_visible visible" "RAM" "$(human_bytes "${mem_total:-0}")" "PIDs" "$proc_short" "VIRT" "$virt"
  if [[ "$threads_available" =~ ^[0-9]+$ && "$threads_visible" =~ ^[0-9]+$ && "$threads_available" -lt "$threads_visible" ]]; then
    info "CPU access limited: $threads_available of $threads_visible visible threads are available · affinity $allowed"
  fi
  if [[ "$virt" != "Bare metal" ]]; then
    printf '\n'
    grid2 "CPU-Limit" "$cpulimit" "RAM-Limit" "$memlimit"
  fi
}
# ---------- CPU sampling ----------
declare -A CPU_TOTAL_1 CPU_IDLE_1 CPU_TOTAL_2 CPU_IDLE_2 CPU_USAGE CPU_MHZ
CPU_GLOBAL_USER=0
CPU_GLOBAL_SYSTEM=0
CPU_GLOBAL_IDLE=0
CPU_GLOBAL_IOWAIT=0
CPU_GLOBAL_STEAL=0

read_cpu_snapshot() {
  local target="$1"
  local cpu user nice system idle iowait irq softirq steal guest guest_nice total idle_all

  while read -r cpu user nice system idle iowait irq softirq steal guest guest_nice; do
    [[ "$cpu" =~ ^cpu([0-9]+)?$ ]] || continue
    user=${user:-0}; nice=${nice:-0}; system=${system:-0}; idle=${idle:-0}
    iowait=${iowait:-0}; irq=${irq:-0}; softirq=${softirq:-0}; steal=${steal:-0}
    total=$((user + nice + system + idle + iowait + irq + softirq + steal))
    idle_all=$((idle + iowait))
    if [[ "$target" == "first" ]]; then
      CPU_TOTAL_1["$cpu"]=$total
      CPU_IDLE_1["$cpu"]=$idle_all
    else
      CPU_TOTAL_2["$cpu"]=$total
      CPU_IDLE_2["$cpu"]=$idle_all
    fi
  done < /proc/stat
}

sample_cpu_usage() {
  local a_user a_nice a_system a_idle a_iowait a_irq a_softirq a_steal _
  local b_user b_nice b_system b_idle b_iowait b_irq b_softirq b_steal
  local total_delta key total_diff idle_diff

  read -r _ a_user a_nice a_system a_idle a_iowait a_irq a_softirq a_steal _ < <(head -n1 /proc/stat)
  read_cpu_snapshot first
  sleep "$CPU_SAMPLE_SECONDS"
  read -r _ b_user b_nice b_system b_idle b_iowait b_irq b_softirq b_steal _ < <(head -n1 /proc/stat)
  read_cpu_snapshot second

  total_delta=$(((b_user-a_user) + (b_nice-a_nice) + (b_system-a_system) + (b_idle-a_idle) + (b_iowait-a_iowait) + (b_irq-a_irq) + (b_softirq-a_softirq) + (b_steal-a_steal)))
  if ((total_delta > 0)); then
    CPU_GLOBAL_USER=$(awk -v n="$(((b_user-a_user)+(b_nice-a_nice)))" -v d="$total_delta" 'BEGIN{printf "%.1f",100*n/d}')
    CPU_GLOBAL_SYSTEM=$(awk -v n="$(((b_system-a_system)+(b_irq-a_irq)+(b_softirq-a_softirq)))" -v d="$total_delta" 'BEGIN{printf "%.1f",100*n/d}')
    CPU_GLOBAL_IDLE=$(awk -v n="$((b_idle-a_idle))" -v d="$total_delta" 'BEGIN{printf "%.1f",100*n/d}')
    CPU_GLOBAL_IOWAIT=$(awk -v n="$((b_iowait-a_iowait))" -v d="$total_delta" 'BEGIN{printf "%.1f",100*n/d}')
    CPU_GLOBAL_STEAL=$(awk -v n="$((b_steal-a_steal))" -v d="$total_delta" 'BEGIN{printf "%.1f",100*n/d}')
  fi

  for key in "${!CPU_TOTAL_2[@]}"; do
    total_diff=$((CPU_TOTAL_2[$key] - CPU_TOTAL_1[$key]))
    idle_diff=$((CPU_IDLE_2[$key] - CPU_IDLE_1[$key]))
    if ((total_diff > 0)); then
      CPU_USAGE["$key"]=$(awk -v t="$total_diff" -v i="$idle_diff" 'BEGIN{printf "%.1f",100*(t-i)/t}')
    else
      CPU_USAGE["$key"]="0.0"
    fi
  done

  local current_cpu current_mhz
  current_cpu=""
  while IFS= read -r line; do
    case "$line" in
      processor*) current_cpu=$(awk -F: '{gsub(/[[:space:]]/,"",$2); print $2}' <<<"$line") ;;
      "cpu MHz"*)
        current_mhz=$(awk -F: '{gsub(/^[[:space:]]+/,"",$2); printf "%.0f",$2}' <<<"$line")
        [[ -n "$current_cpu" ]] && CPU_MHZ["cpu$current_cpu"]="$current_mhz"
        ;;
    esac
  done < /proc/cpuinfo
}

lscpu_value() {
  local key="$1"
  lscpu 2>/dev/null | awk -F: -v k="$key" '{
    name=$1; gsub(/^[[:space:]]+|[[:space:]]+$/, "", name);
    if (name == k) {value=$2; sub(/^[[:space:]]+/, "", value); print value; exit}
  }'
}


cpu_governors() {
  local governors=() file value
  for file in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
    [[ -r "$file" ]] || continue
    value=$(cat "$file" 2>/dev/null || true)
    [[ -n "$value" && " ${governors[*]:-} " != *" $value "* ]] && governors+=("$value")
  done
  ((${#governors[@]})) && printf '%s' "${governors[*]}" || printf 'unavailable'
}

cpu_freq_range() {
  local min_khz="" max_khz="" file value
  for file in /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_min_freq; do
    [[ -r "$file" ]] || continue
    value=$(cat "$file" 2>/dev/null || true)
    [[ "$value" =~ ^[0-9]+$ ]] || continue
    [[ -z "$min_khz" || "$value" -lt "$min_khz" ]] && min_khz="$value"
  done
  for file in /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq; do
    [[ -r "$file" ]] || continue
    value=$(cat "$file" 2>/dev/null || true)
    [[ "$value" =~ ^[0-9]+$ ]] || continue
    [[ -z "$max_khz" || "$value" -gt "$max_khz" ]] && max_khz="$value"
  done
  if [[ -n "$min_khz" && -n "$max_khz" ]]; then
    awk -v min="$min_khz" -v max="$max_khz" 'BEGIN{printf "%.2f–%.2f GHz",min/1000000,max/1000000}'
  else
    printf 'unavailable'
  fi
}

cpu_average_mhz() {
  awk -F: '/cpu MHz/ {sum+=$2; n++} END {if(n) printf "%.0f MHz",sum/n; else print "unavailable"}' /proc/cpuinfo
}

cpu_temperature() {
  local output temp
  if safe_cmd sensors; then
    output=$(sensors 2>/dev/null || true)
    temp=$(awk '
      /Package id 0:|Tctl:|Tdie:|CPU Temperature:|temp1:/ {
        for(i=1;i<=NF;i++) if($i ~ /^\+[0-9.]+°C$/) {gsub(/[+°C]/,"",$i); print $i; exit}
      }' <<<"$output")
    [[ -n "$temp" ]] && { printf '%s °C' "$temp"; return; }
  fi

  local zone raw max=""
  for zone in /sys/class/thermal/thermal_zone*/temp; do
    [[ -r "$zone" ]] || continue
    raw=$(cat "$zone" 2>/dev/null || true)
    [[ "$raw" =~ ^[0-9]+$ ]] || continue
    ((raw > 1000)) && raw=$((raw / 1000))
    [[ -z "$max" || "$raw" -gt "$max" ]] && max="$raw"
  done
  [[ -n "$max" ]] && printf '%s °C' "$max" || printf 'unavailable'
}

cpu_flags_summary() {
  local flags
  flags=$(awk -F: '/^flags|^Features/ {print $2; exit}' /proc/cpuinfo)
  local out=() f
  for f in aes avx avx2 avx512f svm vmx sse4_2 sha_ni; do
    grep -qw "$f" <<<"$flags" && out+=("$f")
  done
  ((${#out[@]})) && printf '%s' "${out[*]}" || printf 'unavailable'
}

show_cpu_overview() {
  section "CPU"
  sample_cpu_usage

  local model sockets cores_socket threads_core available visible load1 load5 load15 temp l3 numa flags topo clock phys_cores allowed
  model=$(lscpu_value 'Model name')
  sockets=$(lscpu_value 'Socket(s)')
  cores_socket=$(lscpu_value 'Core(s) per socket')
  threads_core=$(lscpu_value 'Thread(s) per core')
  l3=$(lscpu_value 'L3 cache')
  numa=$(lscpu_value 'NUMA node(s)')
  available=$(cpu_available_threads)
  visible=$(cpu_visible_threads)
  CPU_THREADS_RAW="$available"
  CPU_THREADS_AVAILABLE_RAW="$available"
  CPU_THREADS_VISIBLE_RAW="$visible"
  CPU_MODEL_RAW="${model:-Unknown}"
  read -r load1 load5 load15 _ < /proc/loadavg
  temp=$(cpu_temperature)
  flags=$(cpu_flags_summary)
  if [[ "$sockets" =~ ^[0-9]+$ && "$cores_socket" =~ ^[0-9]+$ ]]; then phys_cores=$((sockets*cores_socket)); else phys_cores="?"; fi
  if ((TERM_WIDTH < 50)); then
    topo="${phys_cores}C · ${visible}T visible · ${available}T available"
  else
    topo="${phys_cores} cores · ${visible} threads visible · ${available} available"
  fi
  clock="$(cpu_average_mhz) · $(cpu_governors)"

  wide_value "CPU MODEL" "${model:-Unknown}" "$SKY"
  printf '\n'
  stat_grid 4 "TOPOLOGY" "$topo" "CLOCK / GOVERNOR" "$clock" "L3 / NUMA" "${l3:-?} · NUMA ${numa:-?}" "LOAD 1 / 5 / 15" "$load1 · $load5 · $load15"
  printf '\n'
  grid2 "Features" "$flags" "TEMPERATURE" "$temp"

  subsection "LIVE UTILIZATION"
  cpu_mix_bar "$CPU_GLOBAL_USER" "$CPU_GLOBAL_SYSTEM" "$CPU_GLOBAL_IOWAIT" "$CPU_GLOBAL_STEAL"

  subsection "CPU-THREADS"
  local cpu_keys=() allowed_keys=() key idx col cols
  while IFS= read -r key; do allowed_keys+=("$key"); done < <(cpu_allowed_keys)
  if ((${#allowed_keys[@]} > 0)); then
    for key in "${allowed_keys[@]}"; do [[ -n "${CPU_USAGE[$key]+x}" ]] && cpu_keys+=("$key"); done
  else
    while IFS= read -r key; do cpu_keys+=("$key"); done < <(printf '%s\n' "${!CPU_USAGE[@]}" | grep -E '^cpu[0-9]+$' | sort -V)
  fi

  cpu_render_line() {
    local c="$1" usage mhz ghz
    usage="${CPU_USAGE[$c]:-0}"
    mhz="${CPU_MHZ[$c]:-0}"
    ghz=$(awk -v m="$mhz" 'BEGIN{if(m>0)printf "%.1fG",m/1000;else print "-"}')
    if [[ "$LAYOUT_MODE" == "compact" ]]; then
      printf '%b%-5s%b %b%3.0f%%%b %b%4s%b' "$CYAN" "${c^^}" "$RESET" "$WHITE$BOLD" "$usage" "$RESET" "$MUTED" "$ghz" "$RESET"
    else
      printf '%b%-5s%b ' "$CYAN" "${c^^}" "$RESET"
      bar "$usage" 8 "$CYAN"
      printf ' %b%3.0f%%%b %b%4s%b' "$WHITE$BOLD" "$usage" "$RESET" "$MUTED" "$ghz" "$RESET"
    fi
  }

  if [[ "$LAYOUT_MODE" == "compact" ]]; then
    if ((TERM_WIDTH < 50)); then cols=1; else cols=2; fi
  elif ((TERM_WIDTH < 96)); then cols=2
  else cols=$(((TERM_WIDTH - 2) / 28)); ((cols > 5)) && cols=5; ((cols < 3)) && cols=3
  fi
  for ((idx=0; idx<${#cpu_keys[@]}; idx+=cols)); do
    printf '  '
    for ((col=0; col<cols && idx+col<${#cpu_keys[@]}; col++)); do
      cpu_render_line "${cpu_keys[$((idx+col))]}"
      if ((col + 1 < cols && idx + col + 1 < ${#cpu_keys[@]})); then
        [[ "$LAYOUT_MODE" == "compact" ]] && printf '  %b│%b  ' "$BORDER" "$RESET" || printf '   '
      fi
    done
    printf '\n'
  done
  if [[ "$available" =~ ^[0-9]+$ && "$visible" =~ ^[0-9]+$ && "$available" -lt "$visible" ]]; then
    allowed=$(cpu_allowed_list)
    info "Display limited to available CPUs${allowed:+ · affinity $allowed}"
  fi
}

show_top_processes() {
  section "TOP PROCESSES"
  if ((TERM_WIDTH < 96)); then
    local procw=$((TERM_WIDTH - 36)); ((procw < 7)) && procw=7; ((procw > 32)) && procw=32
    printf '  %b%-7s %6s %6s %9s %-*s%b\n' "$BG_PURPLE$WHITE$BOLD" "PID" "CPU%" "MEM%" "RAM" "$procw" "PROCESS" "$RESET"
    ps -eo pid=,%cpu=,%mem=,rss=,comm= --sort=-%cpu 2>/dev/null | awk -v max="$TOP_COUNT" -v pw="$procw" '
      $5 !~ /^(ps|head|awk)$/ && shown < max {
        rss=$4*1024; split("B KiB MiB GiB TiB",u," "); i=1;
        while(rss>=1024 && i<5){rss/=1024;i++}
        printf "  %-7s %6s %6s %6.1f %-3s %-*.*s\n",$1,$2,$3,rss,u[i],pw,pw,$5; shown++
      }' || warn "Process list is unavailable in this environment"
  else
    local namew=$((TERM_WIDTH - 79)); ((namew<24))&&namew=24; ((namew>64))&&namew=64
    printf '  %b%b %-7s %-11s %7s %7s %10s %11s %-5s %-*s %b\n' "$BG_PURPLE" "$WHITE$BOLD" "PID" "USER" "CPU%" "MEM%" "RAM" "ELAPSED" "STAT" "$namew" "PROCESS" "$RESET"
    ps -eo pid=,user=,%cpu=,%mem=,rss=,etime=,stat=,comm= --sort=-%cpu 2>/dev/null | awk -v max="$TOP_COUNT" -v nw="$namew" '
      $8 !~ /^(ps|head|awk)$/ && shown < max {
        rss=$5*1024; split("B KiB MiB GiB TiB",u," "); i=1;
        while(rss>=1024 && i<5){rss/=1024;i++}
        printf "  %-7s %-11.11s %7s %7s %7.1f %-3s %11s %-5.5s %-*.*s\n",$1,$2,$3,$4,rss,u[i],$6,$7,nw,nw,$8; shown++
      }' || warn "Process list is unavailable in this environment"
  fi
  printf '  %b%s%b\n' "$BORDER" "$(repeat_char '─' "$((TERM_WIDTH-2))")" "$RESET"
}


# ---------- Memory ----------
show_memory() {
  section "MEMORY"
  local mem_total mem_used mem_free mem_shared mem_cache mem_available
  local swap_total swap_used swap_free mem_pct swap_pct cpu_psi mem_psi io_psi
  read -r _ mem_total mem_used mem_free mem_shared mem_cache mem_available < <(free -b | awk '/^Mem:/ {print $1,$2,$3,$4,$5,$6,$7}')
  read -r _ swap_total swap_used swap_free < <(free -b | awk '/^Swap:/ {print $1,$2,$3,$4}')
  mem_used=$((mem_total - mem_available))
  mem_pct=$(percent_of "$mem_used" "$mem_total")
  swap_pct=$(percent_of "$swap_used" "$swap_total")
  RAM_TOTAL_BYTES_RAW="$mem_total"
  SWAP_TOTAL_BYTES_RAW="$swap_total"
  MEM_USED_PCT_RAW="$mem_pct"

  stat_grid 4 "RAM USED" "$(human_bytes "$mem_used") / $(human_bytes "$mem_total")" "AVAILABLE" "$(human_bytes "$mem_available")" "CACHE" "$(human_bytes "$mem_cache")" "SWAP" "$(human_bytes "$swap_used") / $(human_bytes "$swap_total")"
  printf '\n'
  wide_bar "RAM" "$mem_pct" "$(human_bytes "$mem_used") used · $(human_bytes "$mem_available") available"
  ((swap_total > 0)) && wide_bar "SWAP" "$swap_pct" "$(human_bytes "$swap_used") / $(human_bytes "$swap_total")"
  if awk -v c="$mem_cache" -v t="$mem_total" 'BEGIN{exit !(t>0 && c/t>0.20)}'; then
    info "Linux file cache ($(human_bytes "$mem_cache")) is largely reclaimable and is not equivalent to actively used application memory."
  fi

  if [[ -r /proc/pressure/cpu ]]; then
    cpu_psi=$(awk '/^some/ {for(i=1;i<=NF;i++) if($i ~ /^avg10=/){split($i,a,"=");print a[2]}}' /proc/pressure/cpu)
    mem_psi=$(awk '/^some/ {for(i=1;i<=NF;i++) if($i ~ /^avg10=/){split($i,a,"=");print a[2]}}' /proc/pressure/memory)
    io_psi=$(awk '/^some/ {for(i=1;i<=NF;i++) if($i ~ /^avg10=/){split($i,a,"=");print a[2]}}' /proc/pressure/io)
    MEM_PSI_RAW="${mem_psi:-0}"
    IO_PSI_RAW="${io_psi:-0}"
    printf '  %bPSI%b  CPU %s%% · RAM %s%% · I/O %s%%\n' "$MUTED" "$RESET" "${cpu_psi:-0}" "${mem_psi:-0}" "${io_psi:-0}"
  fi

}


# ---------- Disk ----------
target_backing_devices() {
  local source="$1" name line found=0
  if [[ -n "$source" && -e "$source" ]]; then
    while IFS= read -r name; do
      [[ -n "$name" ]] || continue
      line=$(lsblk -d -n -o NAME,SIZE,MODEL "/dev/$name" 2>/dev/null | xargs || true)
      [[ -n "$line" ]] && { printf '%s\n' "$line"; found=1; }
    done < <(lsblk -s -n -o NAME,TYPE "$source" 2>/dev/null | awk '$2=="disk" {print $1}' | sort -u)
  fi
  if ((found == 0)); then
    lsblk -d -n -o NAME,SIZE,MODEL,TYPE 2>/dev/null | awk '$NF=="disk" {$NF=""; sub(/[[:space:]]+$/,""); print}'
  fi
}

show_block_devices() {
  section "STORAGE"
  local raw_total target_total target_used target_free target_pct inode_total inode_free inode_pct
  local bench_fs bench_source bench_free mount_options
  raw_total=$(lsblk -b -d -n -o SIZE,TYPE 2>/dev/null | awk '$2=="disk" {sum+=$1} END {printf "%.0f",sum}')
  DISK_TOTAL_BYTES_RAW="${raw_total:-0}"
  read -r target_total target_used target_free target_pct < <(
    df -B1 --output=size,used,avail,pcent "$DISK_PATH" 2>/dev/null | awk 'NR==2 {gsub(/%/,"",$4); print $1,$2,$3,$4}'
  ) || true
  read -r inode_total inode_free inode_pct < <(
    df --output=itotal,iavail,ipcent "$DISK_PATH" 2>/dev/null | awk 'NR==2 {gsub(/%/,"",$3); print $1,$2,$3}'
  ) || true
  STORAGE_TOTAL=$(human_bytes "${target_total:-0}")
  STORAGE_USED=$(human_bytes "${target_used:-0}")
  STORAGE_FREE=$(human_bytes "${target_free:-0}")
  STORAGE_USE_PCT="${target_pct:-0}%"
  STORAGE_USE_PCT_RAW="${target_pct:-0}"
  bench_fs=$(findmnt -T "$DISK_PATH" -no FSTYPE 2>/dev/null || echo unknown)
  bench_source=$(findmnt -T "$DISK_PATH" -no SOURCE 2>/dev/null || echo unknown)
  mount_options=$(findmnt -T "$DISK_PATH" -no OPTIONS 2>/dev/null || echo unknown)
  local mount_limit=$((TERM_WIDTH * 2))
  if ((${#mount_options} > mount_limit)); then mount_options="${mount_options:0:$((mount_limit-2))}…"; fi
  bench_free=$(df -B1 --output=avail "$DISK_PATH" 2>/dev/null | tail -1 | xargs || echo 0)

  stat_grid 4 "RAW CAPACITY" "$(human_bytes "${raw_total:-0}")" "TEST FILESYSTEM" "$STORAGE_TOTAL" "FREE" "$STORAGE_FREE" "FREE INODES" "$(format_number "${inode_free:-0}")"
  printf '\n'
  local storage_color="$YELLOW" storage_flag=""
  if [[ "${target_pct:-0}" =~ ^[0-9]+$ ]]; then
    if ((target_pct >= 90)); then storage_color="$RED"; storage_flag=" · CRITICAL"
    elif ((target_pct >= 80)); then storage_color="$YELLOW"; storage_flag=" · ⚠ HIGH"
    else storage_color="$GREEN"; fi
  fi
  wide_bar "TEST PATH" "${target_pct:-0}" "$STORAGE_USED used · $STORAGE_FREE free · $bench_fs$storage_flag" "$storage_color"
  grid2 "Benchmark target" "$DISK_PATH · $bench_source" "Mount options" "$mount_options"
  if [[ "${target_pct:-0}" =~ ^[0-9]+$ ]]; then
    ((target_pct >= 90)) && fail "Storage is ${target_pct}% used — free space soon or increase capacity."
    ((target_pct >= 80 && target_pct < 90)) && warn "Storage is ${target_pct}% used — keep an eye on free capacity."
  fi

  local devline first=1
  while IFS= read -r devline; do
    [[ -n "$devline" ]] || continue
    if ((first)); then printf '  %bBACKING DEVICE%b  %s
' "$MUTED" "$RESET" "$devline"; first=0
    else printf '  %b              ↳%b  %s
' "$MUTED" "$RESET" "$devline"; fi
  done < <(target_backing_devices "$bench_source")
}


show_smart_health() {
  safe_cmd smartctl || return 0
  [[ $EUID -eq 0 ]] || return 0
  local disks=() name output health temp wear found=0
  while IFS= read -r name; do disks+=("$name"); done < <(lsblk -d -n -o NAME,TYPE 2>/dev/null | awk '$2=="disk" {print $1}' || true)
  ((${#disks[@]} == 0)) && return 0
  subsection "SMART / HEALTH"
  printf '  %b%-12s %-16s %-10s %-10s%b\n' "$DIM" "DEVICE" "STATUS" "TEMP" "WEAR" "$RESET"
  for name in "${disks[@]}"; do
    output=$(smartctl -a "/dev/$name" 2>/dev/null || true)
    health=$(awk -F: '/SMART overall-health self-assessment test result|SMART Health Status/ {gsub(/^[[:space:]]+/,"",$2); print $2; exit}' <<<"$output")
    temp=$(awk '/Temperature_Celsius|Airflow_Temperature_Cel/ {print $10 " °C"; exit} /^Temperature:/ {print $2 " °C"; exit}' <<<"$output")
    wear=$(awk -F: '/Percentage Used:/ {gsub(/^[[:space:]]+/,"",$2); print $2; exit}' <<<"$output")
    [[ -n "$health$temp$wear" ]] && found=1
    printf '  %-12s %-16.16s %-10s %-10s\n' "$name" "${health:-unavailable}" "${temp:--}" "${wear:--}"
  done
  ((found == 0)) && info "On VPS/KVM systems, SMART data from the physical host drive is usually not exposed to the guest."
}


fio_value() {
  local json_file="$1" direction="$2" field="$3"
  jq -r --arg d "$direction" --arg f "$field" '.jobs[0][$d][$f] // 0' "$json_file" 2>/dev/null || echo 0
}

run_fio_case() {
  local title="$1" rw="$2" bs="$3" iodepth="$4" direction="$5"
  local bench_file="$6" output_file="$7"

  local fio_cmd
  fio_cmd=$(get_fio_bin) || { printf '  %-24s %bkein echtes fio gefunden%b\n' "$title" "$RED" "$RESET" >&2; return 1; }
  printf '  %-24s ' "$title" >&2
  if ! "$fio_cmd" \
      --name="slikz-${rw}" \
      --filename="$bench_file" \
      --size="$BENCH_SIZE" \
      --rw="$rw" \
      --bs="$bs" \
      --iodepth="$iodepth" \
      --numjobs=1 \
      --direct=1 \
      --ioengine=libaio \
      --runtime="$BENCH_RUNTIME" \
      --time_based=1 \
      --group_reporting=1 \
      --randrepeat=1 \
      --refill_buffers=1 \
      --output-format=json \
      --output="$output_file" >/dev/null 2>&1; then
    printf '%bfehlgeschlagen%b\n' "$RED" "$RESET" >&2
    return 1
  fi

  local bw iops lat_ns lat_ms
  bw=$(fio_value "$output_file" "$direction" bw_bytes)
  iops=$(fio_value "$output_file" "$direction" iops)
  lat_ns=$(jq -r --arg d "$direction" '.jobs[0][$d].clat_ns.mean // .jobs[0][$d].lat_ns.mean // 0' "$output_file" 2>/dev/null || echo 0)
  lat_ms=$(awk -v n="$lat_ns" 'BEGIN{printf "%.3f",n/1000000}')
  printf '%b%-13s%b  %10.0f IOPS  %8s ms average latency\n' "$GREEN" "$(human_rate "$bw")" "$RESET" "$iops" "$lat_ms" >&2
  printf '%s|%s|%s' "$bw" "$iops" "$lat_ms"
}


run_disk_benchmark() {
  section "DISK BENCH"
  get_fio_bin >/dev/null 2>&1 || { warn "Flexible I/O Tester (fio) is missing, or another program named fio shadows it in PATH."; return 0; }
  safe_cmd jq || { warn "jq is missing — fio JSON output cannot be parsed"; return 0; }

  local fs_type free_bytes required_bytes bench_file
  fs_type=$(findmnt -T "$DISK_PATH" -no FSTYPE 2>/dev/null || echo unknown)
  if [[ "$fs_type" == "tmpfs" || "$fs_type" == "ramfs" ]]; then warn "RAM-backed filesystems are not benchmarked"; return 0; fi
  [[ -d "$DISK_PATH" && -w "$DISK_PATH" ]] || { fail "Not writable: $DISK_PATH"; return 0; }
  free_bytes=$(df -B1 --output=avail "$DISK_PATH" | tail -1 | xargs)
  required_bytes=$([[ "$BENCH_SIZE" == "1G" ]] && echo $((2*1024*1024*1024)) || echo $((768*1024*1024)))
  ((free_bytes >= required_bytes)) || { warn "Not enough free space for the benchmark"; return 0; }

  printf '  %b%s%b\n' "$MUTED" "$BENCH_SIZE · ${BENCH_RUNTIME}s · QD32 · Direct I/O" "$RESET"
  bench_file="$DISK_PATH/.slikz-fio-${$}-${RANDOM}.bin"
  TEMP_FILES+=("$bench_file")
  local out_sw out_sr out_rr out_rw result bw iops lat
  out_sw=$(mktemp); out_sr=$(mktemp); out_rr=$(mktemp); out_rw=$(mktemp)
  TEMP_FILES+=("$out_sw" "$out_sr" "$out_rr" "$out_rw")

  if result=$(run_fio_case "SEQ WRITE 1M" write 1M 32 write "$bench_file" "$out_sw"); then
    IFS='|' read -r bw iops lat <<<"$result"; FIO_SEQ_WRITE_BPS="${bw:-0}"; FIO_SEQ_WRITE_LAT_MS="${lat:-0}"
    [[ "$bw" =~ ^[0-9]+$ && "$bw" -gt 0 ]] && FIO_SEQ_WRITE=$(human_rate "$bw")
  fi

  if result=$(run_fio_case "SEQ READ  1M" read 1M 32 read "$bench_file" "$out_sr"); then
    IFS='|' read -r bw iops lat <<<"$result"; FIO_SEQ_READ_BPS="${bw:-0}"; FIO_SEQ_READ_LAT_MS="${lat:-0}"
    [[ "$bw" =~ ^[0-9]+$ && "$bw" -gt 0 ]] && FIO_SEQ_READ=$(human_rate "$bw")
  fi

  if result=$(run_fio_case "4K RANDOM READ" randread 4K 32 read "$bench_file" "$out_rr"); then
    IFS='|' read -r bw iops lat <<<"$result"; FIO_RAND_READ_IOPS_RAW="${iops:-0}"; FIO_RAND_READ_LAT_MS="${lat:-0}"
    is_number "$iops" && awk -v v="$iops" 'BEGIN{exit !(v>0)}' && FIO_RAND_READ="$(printf '%.0f IOPS' "$iops")"
  fi

  if result=$(run_fio_case "4K RANDOM WRITE" randwrite 4K 32 write "$bench_file" "$out_rw"); then
    IFS='|' read -r bw iops lat <<<"$result"; FIO_RAND_WRITE_IOPS_RAW="${iops:-0}"; FIO_RAND_WRITE_LAT_MS="${lat:-0}"
    is_number "$iops" && awk -v v="$iops" 'BEGIN{exit !(v>0)}' && FIO_RAND_WRITE="$(printf '%.0f IOPS' "$iops")"
  fi

  printf '\n'
  stat_grid 4 "SEQ READ" "$FIO_SEQ_READ" "SEQ WRITE" "$FIO_SEQ_WRITE" "4K READ" "$FIO_RAND_READ" "4K WRITE" "$FIO_RAND_WRITE"
  rm -f -- "$bench_file"
}


# ---------- CPU / memory benchmark ----------
sysbench_cpu_score() {
  local threads="$1"
  sysbench cpu --threads="$threads" --cpu-max-prime=20000 --time="$BENCH_RUNTIME" run 2>/dev/null \
    | awk -F: '/events per second/ {gsub(/^[[:space:]]+/,"",$2); print $2; exit}'
}

run_cpu_benchmark() {
  section "CPU BENCH"
  safe_cmd sysbench || { warn "sysbench is missing — CPU benchmark skipped"; return 0; }
  local threads single multi ratio efficiency total_size memory_out memory_rate memory_num
  threads=$(nproc 2>/dev/null || echo 1)
  CPU_THREADS_RAW="$threads"
  [[ "$MODE" == "quick" && "$threads" -gt 8 ]] && threads=8
  printf '  %b%s%b\n' "$MUTED" "${BENCH_RUNTIME}s · 1T + ${threads}T" "$RESET"

  printf '  %-20s' "SINGLE-THREAD"
  single=$(sysbench_cpu_score 1 || true)
  if is_number "$single"; then
    SYSBENCH_SINGLE_RAW="$single"
    SYSBENCH_SINGLE="$(printf '%.2f events/s' "$single")"; printf '%b%12.2f events/s%b\n' "$GREEN" "$single" "$RESET"
  else printf '%bfehlgeschlagen%b\n' "$RED" "$RESET"; fi

  printf '  %-20s' "MULTI-THREAD"
  multi=$(sysbench_cpu_score "$threads" || true)
  if is_number "$multi"; then
    SYSBENCH_MULTI_RAW="$multi"
    SYSBENCH_MULTI="$(printf '%.2f events/s' "$multi")"; ratio=$(awk -v m="$multi" -v s="${single:-0}" 'BEGIN{if(s>0)printf "%.2f",m/s;else print 0}')
    SYSBENCH_RATIO_RAW="$ratio"
    efficiency=$(awk -v r="$ratio" -v t="$threads" 'BEGIN{if(t>0)printf "%.0f",100*r/t;else print 0}')
    printf '%b%12.2f events/s%b  %b%0.2fx · %s%% scaling%b\n' "$GREEN" "$multi" "$RESET" "$DIM" "$ratio" "$efficiency" "$RESET"
  else printf '%bfehlgeschlagen%b\n' "$RED" "$RESET"; fi

  printf '  %-20s' "MEMORY THROUGHPUT"
  total_size="10G"; [[ "$MODE" == "quick" ]] && total_size="2G"
  memory_out=$(sysbench memory --threads="$threads" --memory-block-size=1M --memory-total-size="$total_size" run 2>/dev/null || true)
  memory_rate=$(awk -F'[()]' '/transferred/ {gsub(/^[[:space:]]+|[[:space:]]+$/,"",$2); print $2; exit}' <<<"$memory_out")
  memory_num=$(awk -F'[()]' '/transferred/ {x=$2; gsub(/^[[:space:]]+|[[:space:]]+$/,"",x); split(x,a," "); print a[1]; exit}' <<<"$memory_out")
  if [[ -n "$memory_rate" ]]; then
    SYSBENCH_MEMORY="$memory_rate"; SYSBENCH_MEMORY_RAW="${memory_num:-0}"; printf '%b%18s%b\n' "$GREEN" "$memory_rate" "$RESET"
  else printf '%bfehlgeschlagen%b\n' "$RED" "$RESET"; fi

  printf '\n'
  stat_grid 3 "SINGLE-THREAD" "$SYSBENCH_SINGLE" "MULTI-THREAD" "$SYSBENCH_MULTI" "MEMORY THROUGHPUT" "$SYSBENCH_MEMORY"
}


# ---------- Network ----------
ping_probe() {
  local host="$1" result loss avg
  if ! safe_cmd ping; then printf '%s|%s' '-' '-'; return 0; fi
  result=$(ping -n -c 3 -W 2 "$host" 2>/dev/null || true)
  loss=$(awk -F', ' '/packet loss/ {print $3}' <<<"$result" | awk '{print $1}')
  avg=$(awk -F'=' '/^rtt|^round-trip/ {split($2,a,"/"); gsub(/^[[:space:]]+/,"",a[2]); print a[2]}' <<<"$result")
  printf '%s|%s' "${avg:--}" "${loss:--}"
  return 0
}



download_test() {
  local label="$1" url="$2" result code speed seconds
  printf '  %-18s' "$label" >&2
  result=$(curl -L -sS --connect-timeout 5 --max-time 35 -o /dev/null -w '%{http_code} %{speed_download} %{time_total}' "$url" 2>/dev/null || true)
  read -r code speed seconds <<<"$result"
  if [[ "$code" =~ ^[23][0-9][0-9]$ && "$speed" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
    printf '%b%27s%b  %5.1fs
' "$GREEN" "$(network_rate "${speed%.*}")" "$RESET" "${seconds:-0}" >&2
    printf '%s' "${speed%.*}"
  else printf '%bunavailable%b
' "$YELLOW" "$RESET" >&2; printf '0'; fi
}

upload_test() {
  local label="$1" url="$2" bytes="$3" result code speed seconds
  printf '  %-18s' "$label" >&2
  result=$(
    head -c "$bytes" /dev/zero 2>/dev/null |
      curl -L -sS --connect-timeout 5 --max-time 45 \
        -o /dev/null -w '%{http_code} %{speed_upload} %{time_total}' \
        -H 'Content-Type: application/octet-stream' --data-binary @- "$url" 2>/dev/null || true
  )
  read -r code speed seconds <<<"$result"
  if [[ "$code" =~ ^[23][0-9][0-9]$ && "$speed" =~ ^[0-9]+([.][0-9]+)?$ && "${speed%.*}" -gt 0 ]]; then
    printf '%b%27s%b  %5.1fs\n' "$GREEN" "$(network_rate "${speed%.*}")" "$RESET" "${seconds:-0}" >&2
    printf '%s' "${speed%.*}"
  else
    printf '%bunavailable%b\n' "$YELLOW" "$RESET" >&2
    printf '0'
  fi
}

show_network() {
  section "NETWORK"
  local iface ipv4 ipv6 gateway link_speed rx tx public_ip public_ipv6 asn isp country
  local p_cf p_google p_fra p_ny p_sg cf_avg cf_loss g_avg g_loss fra_avg fra_loss ny_avg ny_loss sg_avg sg_loss
  iface=$(get_primary_interface)
  ipv4=$(get_primary_ipv4 "$iface")
  ipv6=$(get_primary_ipv6 "$iface")
  gateway=$(ip route show default 2>/dev/null | awk 'NR==1 {print $3}' || true)
  link_speed=$(cat "/sys/class/net/$iface/speed" 2>/dev/null || echo '?')
  rx=$(cat "/sys/class/net/$iface/statistics/rx_bytes" 2>/dev/null || echo 0)
  tx=$(cat "/sys/class/net/$iface/statistics/tx_bytes" 2>/dev/null || echo 0)

  public_ip=''; public_ipv6=''; asn=''; isp=''; country=''
  if ((RUN_NETWORK)); then
    if safe_cmd curl; then
      public_ip=$(curl -4 -fsS --connect-timeout 3 --max-time 5 https://api.ipify.org 2>/dev/null || true)
      public_ipv6=$(curl -6 -fsS --connect-timeout 3 --max-time 5 https://api64.ipify.org 2>/dev/null || true)
      if [[ -n "$public_ip" ]] && safe_cmd jq; then
        local ip_json
        ip_json=$(curl -fsS --connect-timeout 3 --max-time 6 "https://ipwho.is/$public_ip" 2>/dev/null || true)
        asn=$(jq -r '.connection.asn // empty' <<<"$ip_json" 2>/dev/null || true)
        isp=$(jq -r '.connection.isp // empty' <<<"$ip_json" 2>/dev/null || true)
        country=$(jq -r '.country // empty' <<<"$ip_json" 2>/dev/null || true)
      fi
    fi
  fi

  stat_grid 4 "INTERFACE" "${iface:-?}" "LINK" "$(link_speed_label "$link_speed")" "PUBLIC IPv4" "${public_ip:-not checked}" "TRAFFIC SINCE BOOT" "↓ $(human_bytes "$rx") · ↑ $(human_bytes "$tx")"
  printf '\n'
  grid2 "Local IPv4" "${ipv4:-none}" "Gateway" "${gateway:-?}"
  grid2 "Local IPv6" "${ipv6:-none}" "Public IPv6" "${public_ipv6:-not checked}"
  grid2 "Provider" "${isp:-unknown}" "ASN / COUNTRY" "AS${asn:-?} · ${country:-?}"

  ((RUN_NETWORK == 0)) && { info "Public network checks were disabled by option."; return 0; }
  safe_cmd ping || { warn "ping is missing — latency tests skipped"; return 0; }

  subsection "LATENCY"
  p_cf=$(ping_probe "1.1.1.1"); IFS='|' read -r cf_avg cf_loss <<<"$p_cf"
  p_google=$(ping_probe "8.8.8.8"); IFS='|' read -r g_avg g_loss <<<"$p_google"
  p_fra=$(ping_probe "speedtest.frankfurt.linode.com"); IFS='|' read -r fra_avg fra_loss <<<"$p_fra"
  p_ny=$(ping_probe "speedtest.newark.linode.com"); IFS='|' read -r ny_avg ny_loss <<<"$p_ny"
  p_sg=$(ping_probe "speedtest.singapore.linode.com"); IFS='|' read -r sg_avg sg_loss <<<"$p_sg"

  [[ "$cf_avg" =~ ^[0-9]+([.][0-9]+)?$ ]] && { NET_PING_AVG="${cf_avg} ms"; NET_PING_AVG_RAW="$cf_avg"; }
  [[ "$fra_avg" =~ ^[0-9]+([.][0-9]+)?$ ]] && PING_FRANKFURT_MS="$fra_avg"
  [[ "$ny_avg" =~ ^[0-9]+([.][0-9]+)?$ ]] && PING_NEWYORK_MS="$ny_avg"
  [[ "$sg_avg" =~ ^[0-9]+([.][0-9]+)?$ ]] && PING_SINGAPORE_MS="$sg_avg"

  stat_grid 5 "CLOUDFLARE" "${cf_avg} ms · ${cf_loss}" "GOOGLE" "${g_avg} ms · ${g_loss}" "FRANKFURT" "${fra_avg} ms · ${fra_loss}" "US EAST" "${ny_avg} ms · ${ny_loss}" "SINGAPORE" "${sg_avg} ms · ${sg_loss}"

  if ((RUN_BENCHMARKS)); then
    subsection "THROUGHPUT"
    local cf_bytes hetzner_bytes upload_bytes cf_url upload_size
    [[ "$MODE" == "quick" ]] && cf_url='https://speed.cloudflare.com/__down?bytes=25000000' || cf_url='https://speed.cloudflare.com/__down?bytes=100000000'
    cf_bytes=$(download_test "Cloudflare ↓" "$cf_url")
    if [[ "$cf_bytes" =~ ^[0-9]+$ && "$cf_bytes" -gt 0 ]]; then NET_CF_SPEED_BPS="$cf_bytes"; NET_CF_SPEED=$(network_rate "$cf_bytes"); fi
    [[ "$MODE" == "quick" ]] && upload_size=10000000 || upload_size=50000000
    upload_bytes=$(upload_test "Cloudflare ↑" "https://speed.cloudflare.com/__up" "$upload_size")
    if [[ "$upload_bytes" =~ ^[0-9]+$ && "$upload_bytes" -gt 0 ]]; then NET_CF_UPLOAD_BPS="$upload_bytes"; NET_CF_UPLOAD=$(network_rate "$upload_bytes"); fi
    if [[ "$MODE" == "full" ]]; then
      hetzner_bytes=$(download_test "Hetzner ↓" "https://fsn1-speed.hetzner.com/100MB.bin")
      if [[ "$hetzner_bytes" =~ ^[0-9]+$ && "$hetzner_bytes" -gt 0 ]]; then NET_HETZNER_SPEED_BPS="$hetzner_bytes"; NET_HETZNER_SPEED=$(network_rate "$hetzner_bytes"); fi
    fi
    printf '\n'
    stat_grid 3 "CLOUDFLARE DOWNLOAD" "$NET_CF_SPEED" "CLOUDFLARE UPLOAD" "$NET_CF_UPLOAD" "HETZNER DOWNLOAD" "$NET_HETZNER_SPEED"
  fi
}



# ---------- Optional live I/O ----------
show_io_snapshot() {
  safe_cmd iostat || return 0
  section "LIVE I/O"
  printf '  %b%-10s %10s %10s %9s %8s%b\n' "$DIM" "DEVICE" "READ/s" "WRITE/s" "AWAIT" "UTIL%" "$RESET"
  iostat -dxk 1 2 2>/dev/null | awk '/^Device/ {block++; next} block==2 && NF>10 && $1 !~ /^(loop|ram)/ {printf "  %-10s %9.1fK %9.1fK %8.2f %7.1f\n",$1,$3,$9,($6+$12)/2,$NF}' || true
}



# ---------- Automatic analysis / scoring ----------
calculate_scores() {
  local cpu="-" ram="-" disk="-" net="-" total

  if is_number "$SYSBENCH_SINGLE_RAW" && awk -v v="$SYSBENCH_SINGLE_RAW" 'BEGIN{exit !(v>0)}'; then
    cpu=$(awk -v s="$SYSBENCH_SINGLE_RAW" -v m="$SYSBENCH_MULTI_RAW" -v t="$CPU_THREADS_RAW" -v st="$CPU_GLOBAL_STEAL" 'BEGIN{
      if(s>=1000)a=100; else if(s>=750)a=90; else if(s>=550)a=80; else if(s>=400)a=70; else if(s>=280)a=58; else if(s>=180)a=45; else a=32;
      e=(s>0 && t>0)?(m/(s*t))*100:60; if(e>100)e=100;
      if(e>=85)b=100; else if(e>=75)b=90; else if(e>=65)b=80; else if(e>=55)b=68; else if(e>=45)b=55; else b=40;
      p=(st<1?0:(st<3?4:(st<5?8:(st<10?18:30))));
      x=(a*0.72+b*0.28)-p; if(x<0)x=0; if(x>100)x=100; printf "%.0f",x
    }')
  fi

  ram=$(awk -v used="$MEM_USED_PCT_RAW" -v psi="$MEM_PSI_RAW" 'BEGIN{
    x=100; if(used>=90)x-=45; else if(used>=80)x-=25; else if(used>=70)x-=12; else if(used>=60)x-=5;
    if(psi>=10)x-=30; else if(psi>=5)x-=18; else if(psi>=1)x-=7;
    if(x<0)x=0; printf "%.0f",x
  }')

  if is_number "$FIO_SEQ_READ_BPS" && awk -v v="$FIO_SEQ_READ_BPS" 'BEGIN{exit !(v>0)}'; then
    disk=$(awk -v seq="$FIO_SEQ_READ_BPS" -v iops="$FIO_RAND_READ_IOPS_RAW" -v lat="$FIO_RAND_READ_LAT_MS" 'BEGIN{
      mib=seq/1048576;
      if(mib>=1500)a=100; else if(mib>=900)a=92; else if(mib>=500)a=82; else if(mib>=250)a=68; else if(mib>=120)a=52; else a=35;
      if(iops>=100000)b=100; else if(iops>=50000)b=92; else if(iops>=20000)b=82; else if(iops>=10000)b=72; else if(iops>=5000)b=62; else if(iops>=2000)b=48; else b=32;
      if(lat>0 && lat<=0.25)c=100; else if(lat<=0.6)c=90; else if(lat<=1.5)c=78; else if(lat<=4)c=62; else c=45;
      x=a*0.35+b*0.50+c*0.15; if(x>100)x=100; printf "%.0f",x
    }')
  fi

  if is_number "$NET_CF_SPEED_BPS" && awk -v v="$NET_CF_SPEED_BPS" 'BEGIN{exit !(v>0)}'; then
    net=$(awk -v b="$NET_CF_SPEED_BPS" -v p="$NET_PING_AVG_RAW" 'BEGIN{
      mbps=(b*8)/1000000;
      if(mbps>=2000)a=100; else if(mbps>=1000)a=92; else if(mbps>=500)a=82; else if(mbps>=250)a=72; else if(mbps>=100)a=62; else if(mbps>=50)a=48; else a=32;
      if(p<=0)c=60; else if(p<2)c=100; else if(p<5)c=96; else if(p<10)c=90; else if(p<20)c=82; else if(p<40)c=68; else if(p<80)c=52; else c=35;
      printf "%.0f",a*0.60+c*0.40
    }')
  fi

  SCORE_CPU="$cpu"; SCORE_RAM="$ram"; SCORE_DISK="$disk"; SCORE_NET="$net"
  total=$(awk -v c="$cpu" -v r="$ram" -v d="$disk" -v n="$net" 'BEGIN{
    sum=0; w=0; measured=0;
    if(c!="-"){sum+=c*35;w+=35;measured++}
    if(r!="-"){sum+=r*15;w+=15;measured++}
    if(d!="-"){sum+=d*30;w+=30;measured++}
    if(n!="-"){sum+=n*20;w+=20;measured++}
    if(measured>=3 && w>0)printf "%.0f",sum/w; else print "-"
  }')
  SCORE_TOTAL="$total"
}

show_price_insights() {
  [[ -n "$PRICE_EUR" ]] || return 0
  local ram_gib disk_gib cpu_count per_cpu per_ram per_disk ram_per_euro disk_per_euro
  ram_gib=$(awk -v b="$RAM_TOTAL_BYTES_RAW" 'BEGIN{printf "%.1f",b/1073741824}')
  disk_gib=$(awk -v b="$DISK_TOTAL_BYTES_RAW" 'BEGIN{printf "%.1f",b/1073741824}')
  cpu_count="${CPU_THREADS_RAW:-0}"
  per_cpu=$(awk -v p="$PRICE_EUR" -v c="$cpu_count" 'BEGIN{if(c>0)printf "%.2f",p/c;else print "-"}')
  per_ram=$(awk -v p="$PRICE_EUR" -v r="$ram_gib" 'BEGIN{if(r>0)printf "%.2f",p/r;else print "-"}')
  per_disk=$(awk -v p="$PRICE_EUR" -v d="$disk_gib" 'BEGIN{if(d>0)printf "%.3f",p/d;else print "-"}')
  ram_per_euro=$(awk -v p="$PRICE_EUR" -v r="$ram_gib" 'BEGIN{if(p>0)printf "%.2f",r/p;else print "-"}')
  disk_per_euro=$(awk -v p="$PRICE_EUR" -v d="$disk_gib" 'BEGIN{if(p>0)printf "%.1f",d/p;else print "-"}')

  subsection "PRICE / RESOURCES"
  stat_grid 4 "MONTHLY PRICE" "$(printf '%.2f €' "$PRICE_EUR")" "PRICE / vCPU" "$per_cpu €" "PRICE / GiB RAM" "$per_ram €" "PRICE / GiB DISK" "$per_disk €"
  printf '\n'
  stat_grid 3 "PER €1 · RAM" "${ram_per_euro} GiB" "PER €1 · DISK" "${disk_per_euro} GiB" "AVAILABLE vCPU" "$cpu_count Threads"
  info "Price context only compares resource quantity; SLA, traffic, backups, DDoS protection and CPU fair-share policies are not included."
}


show_insights() {
  calculate_scores
  section "INSIGHTS"
  info "Scores are heuristic summaries derived from measurements collected in this run; raw benchmark values remain the primary reference."
  local total="${SCORE_TOTAL:-}" cpu="${SCORE_CPU:-}" disk="${SCORE_DISK:-}" net="${SCORE_NET:-}" measured=0
  [[ "$SCORE_CPU" != "-" ]] && measured=$((measured+1))
  [[ "$SCORE_RAM" != "-" ]] && measured=$((measured+1))
  [[ "$SCORE_DISK" != "-" ]] && measured=$((measured+1))
  [[ "$SCORE_NET" != "-" ]] && measured=$((measured+1))
  [[ "$total" == "-" ]] && total="–" || total="${total}/100"
  [[ "$cpu" == "-" ]] && cpu="–" || cpu="${cpu}/100"
  [[ "$disk" == "-" ]] && disk="–" || disk="${disk}/100"
  [[ "$net" == "-" ]] && net="–" || net="${net}/100"
  stat_grid 4 "HEURISTIC SCORE" "$total" "CPU" "$cpu" "DISK" "$disk" "NETWORK" "$net"
  printf '\n'

  if ((measured < 3)); then
    if ((RUN_BENCHMARKS == 0)); then
      insight info "Benchmark mode" "Load benchmarks were disabled, so no overall performance score is calculated."
    else
      insight warn "Incomplete analysis" "$measured/4 score areas measured. Missing or unavailable benchmark data prevents a meaningful overall score."
    fi
  elif [[ "$SCORE_TOTAL" =~ ^[0-9]+$ ]]; then
    if ((SCORE_TOTAL >= 85)); then insight good "Overall assessment" "Very strong measured performance for the resources visible to this VPS."
    elif ((SCORE_TOTAL >= 70)); then insight good "Overall assessment" "Good, balanced performance with no obvious primary bottleneck."
    elif ((SCORE_TOTAL >= 50)); then insight warn "Overall assessment" "Solid baseline, but at least one area is a noticeable bottleneck."
    else insight bad "Overall assessment" "Several measured values are well below a strong VPS baseline."
    fi
  fi

  if awk -v s="$CPU_GLOBAL_STEAL" 'BEGIN{exit !(s<1)}'; then
    insight good "CPU-Steal" "${CPU_GLOBAL_STEAL}% — no meaningful host CPU contention detected in this sample."
  elif awk -v s="$CPU_GLOBAL_STEAL" 'BEGIN{exit !(s<5)}'; then
    insight warn "CPU-Steal" "${CPU_GLOBAL_STEAL}% — light host contention; monitor it under load."
  else
    insight bad "CPU-Steal" "${CPU_GLOBAL_STEAL}% — strong indication of CPU contention on the virtualization host."
  fi

  if awk -v m="$MEM_USED_PCT_RAW" 'BEGIN{exit !(m<70)}'; then
    insight good "Memory headroom" "${MEM_USED_PCT_RAW}% used — healthy headroom in the current snapshot."
  elif awk -v m="$MEM_USED_PCT_RAW" 'BEGIN{exit !(m<85)}'; then
    insight warn "Memory headroom" "${MEM_USED_PCT_RAW}% used — headroom is getting tight, especially without swap."
  else
    insight bad "Memory headroom" "${MEM_USED_PCT_RAW}% used — memory pressure is likely."
  fi

  if [[ "$STORAGE_USE_PCT_RAW" =~ ^[0-9]+$ ]]; then
    if ((STORAGE_USE_PCT_RAW >= 90)); then insight bad "Storage headroom" "${STORAGE_USE_PCT_RAW}% used — critically low free capacity on the test filesystem."
    elif ((STORAGE_USE_PCT_RAW >= 80)); then insight warn "Storage headroom" "${STORAGE_USE_PCT_RAW}% used — still usable, but watch growth and logs."
    else insight good "Storage headroom" "${STORAGE_USE_PCT_RAW}% used — healthy free capacity."
    fi
  fi

  if ((SWAP_TOTAL_BYTES_RAW == 0)); then
    insight info "Swap" "No swap is configured. This is common on small VPS instances, but it leaves less buffer before the OOM killer during real memory exhaustion."
  else
    insight good "Swap" "Swap is present; the important signal is whether it stays heavily used under normal load."
  fi

  if ((RUN_NETWORK == 0)); then
    insight info "Network checks" "Public network checks were disabled for this run."
  elif [[ "$NET_PING_AVG_RAW" =~ ^[0-9]+([.][0-9]+)?$ ]] && awk -v p="$NET_PING_AVG_RAW" 'BEGIN{exit !(p>0)}'; then
    if awk -v p="$NET_PING_AVG_RAW" 'BEGIN{exit !(p<5)}'; then insight good "Network latency" "${NET_PING_AVG} to Cloudflare — excellent for a nearby Anycast endpoint."
    elif awk -v p="$NET_PING_AVG_RAW" 'BEGIN{exit !(p<20)}'; then insight good "Network latency" "${NET_PING_AVG} — very good."
    else insight warn "Network latency" "${NET_PING_AVG} — relatively high for a nearby test endpoint."
    fi
  else
    insight warn "Network latency" "Not fully measured; the ping tool or a target response is missing."
  fi

  if ((RUN_BENCHMARKS)); then
    [[ "$SCORE_CPU" == "-" ]] && insight warn "CPU benchmark" "Not measured. Install sysbench to collect single-thread, multi-thread and scaling results."
    [[ "$SCORE_DISK" == "-" ]] && insight warn "Disk benchmark" "Not measured. Install fio and jq to collect sequential throughput, 4K IOPS and latency."
    ((RUN_NETWORK)) && [[ "$SCORE_NET" == "-" ]] && insight warn "Network throughput" "No complete download test is available; upload alone is not enough for a network score."
  fi

  if [[ "$VIRT_TYPE_RAW" != "Bare metal" && -n "$VIRT_TYPE_RAW" ]]; then
    insight info "Virtualization" "${VIRT_TYPE_RAW}: CPU model and clock data may expose host information; the effective vCPU limits are what matter for this guest."
  fi

  if [[ -n "$PRICE_EUR" ]]; then
    show_price_insights
  fi
}
# ---------- Summary ----------
show_summary() {
  local elapsed total_label
  elapsed=$(($(date +%s) - RUN_STARTED_AT))
  [[ "$SCORE_TOTAL" == "-" ]] && total_label="INSUFFICIENT DATA" || total_label="${SCORE_TOTAL}/100 · $(score_label "$SCORE_TOTAL")"
  section "RESULTS"

  if [[ "$LAYOUT_MODE" == "compact" ]]; then
    kv "HEURISTIC SCORE" "$total_label" "$LIME"
    kv "CPU 1T / MT" "$SYSBENCH_SINGLE / $SYSBENCH_MULTI" "$CYAN"
    kv "DISK R / W" "$FIO_SEQ_READ / $FIO_SEQ_WRITE" "$YELLOW"
    kv "NETWORK ↓ / ↑" "$NET_CF_SPEED / $NET_CF_UPLOAD" "$BLUE"
  else
    printf '  %b%-16s%b %b%s%b\n' "$MUTED" "HEURISTIC SCORE" "$RESET" "$LIME$BOLD" "$total_label" "$RESET"
    stat_grid 3 "CPU · 1T / MT" "$SYSBENCH_SINGLE / $SYSBENCH_MULTI" "DISK · READ / WRITE" "$FIO_SEQ_READ / $FIO_SEQ_WRITE" "NETWORK · DOWN / UP" "$NET_CF_SPEED / $NET_CF_UPLOAD"
  fi

  printf '\n'
  if ((${#MISSING_PACKAGES[@]} > 0)); then
    warn "Missing for a complete report: ${MISSING_PACKAGES[*]}"
    info "Recommended: sudo $0 --full --yes --install-deps"
  elif [[ "$SCORE_TOTAL" == "-" ]]; then
    warn "Not all score areas could be measured in this environment."
  else
    ok "Core analysis completed."
  fi
  ok "done · $(format_seconds "$elapsed") · $(date '+%H:%M:%S') · ${LAYOUT_MODE^^} Layout · ${TERM_WIDTH} columns"
}


confirm_benchmarks() {
  ((RUN_BENCHMARKS == 0 || AUTO_YES == 1)) && return 0
  [[ -t 0 ]] || { RUN_BENCHMARKS=0; return 0; }
  printf '\n%bRun CPU, storage and network benchmarks? [Y/n]%b ' "$YELLOW" "$RESET"
  read -r answer
  case "${answer:-Y}" in n|N|no|NO) RUN_BENCHMARKS=0 ;; esac
}


main() {
  if ((INSTALL_DEPS)); then
    install_dependencies || true
    print_header
  else
    print_header
    install_dependencies || true
  fi

  if [[ ! -e "$DISK_PATH" ]]; then
    fail "Test path does not exist: $DISK_PATH"
    exit 1
  fi

  confirm_benchmarks
  if ((RUN_BENCHMARKS)); then PHASE_TOTAL=10; else PHASE_TOTAL=8; fi

  phase "Collecting system data"
  show_system_overview
  show_effective_limits
  phase "Analyzing CPU"
  show_cpu_overview
  phase "Inspecting processes"
  show_top_processes
  phase "Inspecting memory"
  show_memory
  phase "Inspecting storage"
  show_block_devices
  show_smart_health
  show_io_snapshot
  phase "Testing network"
  show_network

  if ((RUN_BENCHMARKS)); then
    phase "Benchmarking CPU"
    run_cpu_benchmark
    phase "Benchmarking storage"
    run_disk_benchmark
  fi

  phase "Interpreting measurements"
  show_insights
  phase "Building final report"
  show_summary
}


main "$@"
