#!/usr/bin/env bash
# /etc/update-motd.d/99-neve-status   (numbered last so it renders below the
# stock system-information block, right above the shell prompt)
#
# Login MOTD fragment: probe the local neve `/health` endpoint and print a
# two-column status block in the style of Ubuntu's "System information".
# Reports up/down and, when up, port, uptime, sync state, disk, memory, chain,
# and the served block range.
#
# Reads the bind address from /etc/neve/neve.env (--rpc-addr) when present, so
# it follows an operator who moved the port; falls back to neve's default.
# Override explicitly with NEVE_HEALTH_URL=http://host:port.
#
# The block is a point-in-time snapshot taken at login (the "as of" header
# makes the age explicit) — it is not refreshed while the session is open.
#
# Kept fast and quiet: a 2s curl timeout means a hung or missing neve never
# stalls a login. Degrades cleanly if curl or jq is absent.
set -u

# --- locate dependencies -----------------------------------------------------
CURL=$(command -v curl || true)
JQ=$(command -v jq || true)

# --- colors ------------------------------------------------------------------
# Emit the 16-color ANSI codes unconditionally. A MOTD fragment runs inside
# pam_motd's generation environment — no controlling tty, and TERM is typically
# unset or "dumb" — but its output is displayed *later* on the user's real
# login terminal. So no signal available here (`[ -t 1 ]`, $TERM, $NO_COLOR)
# reflects the terminal that will actually render this; gating on any of them
# strips color exactly where we want it (the earlier tty and TERM=dumb gates
# both made this mistake). A MOTD is by definition shown on an interactive
# login terminal, and every such terminal handles 16-color SGR — so just emit.
# NEVE_MOTD_NO_COLOR=1 forces plain output (handy for piping/testing).
if [ -n "${NEVE_MOTD_NO_COLOR:-}" ]; then
  RED=''; GRN=''; YEL=''; CYAN=''; BOLD=''; RST=''
else
  RED=$'\e[31m'; GRN=$'\e[32m'; YEL=$'\e[33m'; CYAN=$'\e[36m'; BOLD=$'\e[1m'; RST=$'\e[0m'
fi

NOW=$(date)

# Two columns per row. Each cell is "label: value"; the left cell is padded to
# a fixed width so the right labels line up, matching the system-info block.
# Colors are measured-out of the pad width so coloring never breaks alignment.
row() {
  local ll="$1" lv="$2" rl="$3" rv="$4" pad=26 vis plain
  plain=$(printf '%s' "$lv" | sed 's/\x1b\[[0-9;]*m//g')   # strip color for width
  vis=$(( pad - ${#ll} - 2 - ${#plain} ))     # 2 = ": "
  (( vis < 1 )) && vis=1
  printf '  %s: %s%*s%s: %s\n' "$ll" "$lv" "$vis" '' "$rl" "$rv"
}

# --- resolve the health URL + display host:port ------------------------------
HEALTH_URL="${NEVE_HEALTH_URL:-}"
addr=127.0.0.1:8545
if [ -z "$HEALTH_URL" ]; then
  if [ -r /etc/neve/neve.env ]; then
    a=$(sed -n 's/.*--rpc-addr[ =]\([^ ]*\).*/\1/p' /etc/neve/neve.env | tail -n1)
    [ -n "$a" ] && addr="$a"
  fi
  probe=${addr/0.0.0.0:/127.0.0.1:}           # neve may bind 0.0.0.0; probe loopback
  probe=${probe/\[::\]:/127.0.0.1:}
  HEALTH_URL="http://${probe}/health"
fi
# Display the port the way an operator types it.
port="$addr"
case "$addr" in
  127.0.0.1:*|0.0.0.0:*|\[::\]:*|\[::1\]:*) port="localhost:${addr##*:}" ;;
esac

# No leading blank line of our own: the preceding MOTD fragment (00-header)
# already ends with one, so that single blank is the separator. A trailing
# blank line *is* printed at the end of each branch below, to separate the
# block from the "Last login" line / shell prompt that follows.
#
# A small "neve" wordmark in bold cyan so the block announces itself instead
# of blending into the stock system-information panel below it. Quoted heredoc
# so the backticks/quotes in the art need no escaping; colored as a whole.
printf '%s' "$BOLD$CYAN"
cat <<'BANNER'
'OoOo. .oOo. `o   O .oOo.
 o   O OooO'  O   o OooO'
 O   o O      o  O  O
 o   O `OoO'  `o'   `OoO'
BANNER
printf '%s\n' "$RST"
printf 'Neve information as of %s:\n\n' "$NOW"

# --- missing curl: can't probe -----------------------------------------------
if [ -z "$CURL" ]; then
  row "status" "${YEL}unknown${RST}" "port" "$port"
  printf '  (curl not installed — cannot probe /health)\n\n'
  exit 0
fi

body=$("$CURL" -fsS --max-time 2 "$HEALTH_URL" 2>/dev/null)
if [ -z "$body" ]; then
  row "status" "${RED}down${RST}" "port" "$port"
  printf '  systemctl status neve  ·  journalctl -u neve -e\n\n'
  exit 0
fi

# --- no jq: confirm up, but the detail rows need jq to parse /health ---------
if [ -z "$JQ" ]; then
  row "status" "${GRN}up${RST}" "port" "$port"
  printf '  %sjq not available%s — install jq for the full status block\n\n' "$YEL" "$RST"
  exit 0
fi

# --- parse one jq pass into shell-readable fields ----------------------------
# shellcheck disable=SC2016  # $id is jq syntax, not a shell variable.
parsed=$("$JQ" -r '
  def chain($id): if $id==43114 then "mainnet"
                  elif $id==43113 then "testnet (Fuji)"
                  else "chain " + ($id|tostring) end;
  [ .status,
    chain(.chain_id),
    (.uptime // "?"),
    (.blocks.min_height // 0 | tostring),
    (.blocks.max_contiguous_height // 0 | tostring),
    (.blocks.high_water // 0 | tostring),
    (.blocks.behind // 0 | tostring),
    (.storage.total_human // "?"),
    (.memory.physical_human // "?"),
    (.version // "?"),
    (.commit // "?")
  ] | @tsv
' <<<"$body" 2>/dev/null)

if [ -z "$parsed" ]; then
  row "status" "${YEL}up${RST}" "port" "$port"
  printf '  (unrecognized /health payload)\n\n'
  exit 0
fi

IFS=$'\t' read -r status chain uptime min mc hw behind disk rss ver commit <<<"$parsed"

# Sync line: caught up vs. how many blocks behind the upstream tip.
if [ "$behind" -eq 0 ] 2>/dev/null; then
  sync="${GRN}caught up${RST}"
else
  sync="${YEL}${behind} blocks behind tip${RST}"
fi

# high_water can run ahead of the contiguous height if newHeads raced backfill.
if [ "$hw" != "$mc" ]; then
  range="${min}–${mc} (hw ${hw})"
else
  range="${min}–${mc}"
fi

# `status` from /health is "ok"; surface it as the operator-facing "up".
[ "$status" = "ok" ] && status_word="${GRN}up${RST}" || status_word="${YEL}${status}${RST}"

row "status"    "$status_word" "port"          "$port"
row "uptime"    "$uptime"      "sync"          "$sync"
row "used disk" "$disk"        "memory"        "$rss"
row "chain"     "$chain"       "blocks served" "$range"
printf '\n  version: v%s (%s)\n  health:  http://%s/health\n  metrics: http://%s/metrics\n  logs:    journalctl -u neve -f\n  updater: sudo /opt/neve/deploy/update.sh\n\n' \
  "$ver" "$commit" "$port" "$port"
