#!/bin/bash
#
# Copyright (c) Authors: https://www.armbian.com/authors
#
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
#

# DO NOT EDIT THIS FILE — use /etc/default/armbian-motd for overrides.

set -o pipefail

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
THIS_SCRIPT="sysinfo"

# Defaults (override in /etc/default/armbian-motd)
MOTD_DISABLE=""
PRIMARY_INTERFACE="eth0"
PRIMARY_DIRECTION="rx"     # rx | tx | both | (anything else to disable)
STORAGE="/dev/sda1"

CPU_TEMP_LIMIT=60
CPU_TEMP_OFFSET=0          # °C offset
HDD_TEMP_LIMIT=60
AMB_TEMP_LIMIT=40

[[ -f /etc/default/armbian-motd ]] && . /etc/default/armbian-motd

for f in ${MOTD_DISABLE}; do
	[[ "$f" == "$THIS_SCRIPT" ]] && exit 0
done

# Optional vendor helpers (ambienttemp, batteryinfo, getboardtemp)
if [[ -r /usr/lib/armbian/armbian-allwinner-battery ]]; then
	# shellcheck disable=SC1091
	. /usr/lib/armbian/armbian-allwinner-battery
fi
# Provide safe no-op stubs if functions are missing
command -v ambienttemp >/dev/null 2>&1 || ambienttemp() { echo ""; }
command -v batteryinfo  >/dev/null 2>&1 || batteryinfo() { :; }
command -v getboardtemp >/dev/null 2>&1 || getboardtemp() { board_temp=""; }

display() {
	# $1=name $2=value $3=red_limit $4=min_show_limit $5=unit $6=after
	# Battery uses inverse threshold (lower is worse)
	local name="$1" val="$2" red="$3" min="$4" unit="$5" after="$6"
	[[ -z "$val" ]] && return 0
	if awk -v v="$val" -v m="$min" -v inv="$name" 'BEGIN{
		 if (v+0 <= 0) exit 1;
		 if (inv=="Battery") exit !(v+0 >= m+0); else exit !(v+0 >= m+0)
	}'; then
		printf "%-14s" "${name}:"
		if awk -v v="$val" -v r="$red" -v inv="$name" 'BEGIN{
			 if (inv=="Battery") exit !(v+0 < r+0); else exit !(v+0 > r+0)
		}'; then
			printf "\e[0;91m %s" "$val"
		else
			printf "\e[0;92m %s" "$val"
		fi
		printf "%s\x1B[0m" "$unit"
		printf "%-11s\t" "$after"
		return 1
	fi
	return 0
}

storage_info() {
	# Root filesystem
	local rootInfo storageInfo
	rootInfo="$(df -hP /)"
	root_usage="$(awk 'NR==2{gsub(/%/,"",$5); print $5}' <<<"$rootInfo")"
	root_total="$(awk 'NR==2{print $2}' <<<"$rootInfo")"

	# Optional extra storage (only if it exists and is not the root FS)
	if df -hP "$STORAGE" &>/dev/null; then
		storageInfo="$(df -hP "$STORAGE" | awk 'NR==2')"
		if [[ -n "$storageInfo" ]] && ! grep -q " $STORAGE " <<<"$rootInfo"; then
			storage_usage="$(awk '{gsub(/%/,"",$5); print $5}' <<<"$storageInfo")"
			storage_total="$(awk '{print $2}' <<<"$storageInfo")"
			if command -v smartctl >/dev/null 2>&1; then
				local disk="${STORAGE%[0-9]}"
				storage_temp="$(smartctl -l scttempsts "$disk" 2>/dev/null \
					| awk -F': *' '/Current Temperature:/ {print $(NF-1)}')"
			fi
		fi
	fi
}

# Collect sensor and storage data
amb_temp="$(ambienttemp)"
batteryinfo
storage_info
getboardtemp
critical_load=80

# Uptime, users, and load
users="$(who 2>/dev/null | wc -l | tr -d ' ')"
time="$(uptime -p 2>/dev/null | sed -e 's/^up //')"
[[ -z "$time" ]] && time="$(LC_ALL=C uptime | sed -E 's/.*up ([^,]+), .*/\1/')"

cpucount="$(grep -c ^processor /proc/cpuinfo 2>/dev/null || echo 1)"
read -r load1 _ < /proc/loadavg
[[ "$load1" == 0.0* ]] && load1="0.10"
load="$(awk -v l="$load1" -v c="$cpucount" 'BEGIN{printf("%.0f",(l/c)*100)}')"

# Memory / swap
read -r mem_total_kb _ < <(awk '/MemTotal:/ {print $2" "$3; exit}' /proc/meminfo)
mem_total_mb="$(( mem_total_kb / 1024 ))"
mem_used_kb="$(awk '
 /MemTotal:/ {t=$2}
 /MemFree:/  {f=$2}
 /Buffers:/  {b=$2}
 /^Cached:/  {c=$2}
 END{printf("%d", t-f-b-c)}
' /proc/meminfo)"
memory_usage="$(awk -v u="$mem_used_kb" -v t="$mem_total_kb" 'BEGIN{printf("%.0f", (u/t)*100)}')"

swap_total_mb="$(awk '/SwapTotal:/ {print int($2/1024)}' /proc/meminfo)"
swap_used_mb="$(awk '/SwapFree:/ {sf=$2} /SwapTotal:/ {st=$2} END{print int((st-sf)/1024)}' /proc/meminfo)"
if [[ "${swap_total_mb:-0}" -gt 0 ]]; then
	swap_usage="$(awk -v u="$swap_used_mb" -v t="$swap_total_mb" 'BEGIN{printf("%3.0f", (u/t)*100)}')"
else
	swap_total_mb=0
	swap_usage=0
fi

# --- spacing before Performance ---
# Add a blank line only if something printed before (e.g., IP, containers, AP)
if [[ -e /run/armbian-motd/.after_header.printed ]] \
   || [[ -e "${XDG_RUNTIME_DIR:-/tmp}/armbian-motd/.after_header.printed" ]]; then
  echo ""
fi
printf "\e[0;90m Performance:  \x1B[0m\n\n"

display " Load"           "${load%% *}" "$critical_load" "0" "%" ""
printf " Uptime:       \x1B[92m%s\x1B[0m\t" "${time:-unknown}"
display " Local users"   "${users:-0}" "3" "2" "" ""
echo ""

# Humanize totals
if (( mem_total_mb > 1000 )); then
	memory_total="$(awk -v m="$mem_total_mb" 'BEGIN{printf("%.2fG", m/1024)}')"
else
	memory_total="${mem_total_mb}M"
fi

if (( swap_total_mb > 500 )); then
	swap_total_disp="$(awk -v s="$swap_total_mb" 'BEGIN{printf("%.2fG", s/1024)}')"
else
	swap_total_disp="${swap_total_mb}M"
fi

display " Memory usage"   "$memory_usage" "70" "0" "%" " of ${memory_total}"
display " Zram usage"     "$swap_usage" "75" "0" "%" " of ${swap_total_disp}"
echo ""

# Temperatures & root usage
# Apply optional CPU temp offset if both numeric
if [[ -n "${board_temp:-}" ]] && awk -v t="$board_temp" -v o="$CPU_TEMP_OFFSET" 'BEGIN{exit !(t ~ /^-?[0-9.]+$/ && o ~ /^-?[0-9.]+$/)}'; then
	board_temp="$(awk -v t="$board_temp" -v o="$CPU_TEMP_OFFSET" 'BEGIN{printf("%.1f", t+o)}')"
fi

# Truncate temperature decimals (e.g. 37.6 → 37)
cpu_temp_int=$(printf '%.0f\n' "${board_temp%%.*}")
amb_temp_int=$(printf '%.0f\n' "${amb_temp%%.*}")

display " CPU temp" "$cpu_temp_int" "$CPU_TEMP_LIMIT" "0" "°C" ""
display " Ambient temp" "$amb_temp_int" "$AMB_TEMP_LIMIT" "0" "°C" ""
display " Usage of /"     "${root_usage:-0}" "90" "1" "%" " of ${root_total} ${overlay_root}"

if command -v overlayroot-chroot >/dev/null 2>&1 && findmnt -k /media/root-ro | tail -1 | grep -qw /media/root-ro; then
	echo -ne "\x1B[91m(read only rootfs)\x1B[0m"
fi
echo ""

# Optional secondary storage / disk temp / battery
a=0
display " storage /"      "${storage_usage:-0}" "90" "1" "%" " of ${storage_total:-}" ; a=$((a+$?))
display " storage temp"   "${storage_temp:-0}" "$HDD_TEMP_LIMIT" "0" "°C" ""      ; a=$((a+$?))
display " Battery"        "${battery_percent:-0}" "20" "1" "%" "${status_battery_text:-}" ; a=$((a+$?))
(( a > 0 )) && echo ""

# vnStat daily traffic (if available)
if [[ -n "$PRIMARY_INTERFACE" ]] && command -v vnstat >/dev/null 2>&1; then
    if vnstat -i "$PRIMARY_INTERFACE" &>/dev/null; then
        # Use C locale so decimals are '.' and units are ASCII.
        line="$(LC_ALL=C vnstat -i "$PRIMARY_INTERFACE" --oneline 2>/dev/null)"
        # Fields 4 and 5 are today's RX;TX totals. They may be like "205.88KiB" or "205.88 KiB".
        rx_raw="$(cut -d';' -f4 <<<"$line")"
        tx_raw="$(cut -d';' -f5 <<<"$line")"

        # Normalize: extract integer value (truncate decimals) and unit; ensure exactly one space.
        norm_val()  { sed -E 's/^([0-9]+)(\.[0-9]+)?([[:space:]]*)([A-Za-z]+).*/\1/'; }
        norm_unit() { sed -E 's/^([0-9]+)(\.[0-9]+)?([[:space:]]*)([A-Za-z]+).*/\4/'; }

        traffic_rx_value="$(printf '%s' "$rx_raw" | norm_val)"
        traffic_rx_unit="$( printf '%s' "$rx_raw" | norm_unit)"
        traffic_tx_value="$(printf '%s' "$tx_raw" | norm_val)"
        traffic_tx_unit="$( printf '%s' "$tx_raw" | norm_unit)"

        # Handle "Not enough" (no data yet)
        if [[ "$rx_raw$tx_raw" == *"Not enough"* ]]; then
            traffic_rx_value="n/a"; traffic_rx_unit=""
            traffic_tx_value="n/a"; traffic_tx_unit=""
        fi

        case "$PRIMARY_DIRECTION" in
            tx)
                display " TX today" "$traffic_tx_value" 500 0 " ${traffic_tx_unit}" "" ;;
            rx)
                display " RX today" "$traffic_rx_value" 500 0 " ${traffic_rx_unit}" "" ;;
            both)
                display " TX today" "$traffic_tx_value" 500 0 " ${traffic_tx_unit}" ""
                display " RX today" "$traffic_rx_value" 500 0 " ${traffic_rx_unit}" "" ;;
            *) : ;;
        esac
        echo ""   # force newline after vnStat output
    fi
fi

# ZFS pool summary
if command -v zpool >/dev/null 2>&1; then
	zpoolstatus="$(zpool status 2>&1 || true)"
	if grep -q 'not loaded' <<<"$zpoolstatus"; then
		: # no line
	elif grep -Eq 'degraded|OFFLINE' <<<"$zpoolstatus"; then
		printf " ZFS pool:     "
		echo -ne "\e[0;91mDegraded\x1B[0m"
		echo ""
	elif grep -q 'no pools available' <<<"$zpoolstatus"; then
		printf " ZFS pool:     "
		echo -ne "n/a"
		echo ""
	else
		printf " ZFS pool:     "
		echo -ne "\e[0;92mOnline\x1B[0m"
		echo ""
	fi
fi

exit 0
