#!/bin/bash
# Uptime Kuma status widget.
# Reads the /metrics endpoint, which needs an API key (Settings > API Keys).
# The key is taken from $KUMA_API_KEY, or else from the login keychain:
#   security add-generic-password -U -s uptime-kuma-widget -a api-key -w
# The server address comes from $KUMA_URL (no trailing slash), e.g. set in the
# LaunchAgent plist's EnvironmentVariables.
TW=/Applications/TerminalWidget.app/Contents/MacOS/TerminalWidget
TW_TARGET="uptime-kuma"
KUMA_URL="${KUMA_URL%/}"
KUMA_API_KEY="${KUMA_API_KEY:-$(/usr/bin/security find-generic-password -s uptime-kuma-widget -a api-key -w 2>/dev/null)}"

OK_BG="#15803d"
DOWN_BG="#b91c1c"
ERR_BG="#475569"
FG="#f8fafc"

show_error() {
  "$TW" --target $TW_TARGET \
    --icon exclamationmark.triangle.fill \
    --text "$1" \
    --fit-text \
    --timestamp \
    --action-kind open-url --action-value "$KUMA_URL/dashboard" \
    --bg "$ERR_BG" \
    --fg "$FG"
  exit 1
}

[ -n "$KUMA_URL" ] || show_error "KUMA_URL not set"
[ -n "$KUMA_API_KEY" ] || show_error "No Uptime Kuma API key"

# Key is passed via a curl config on stdin so it doesn't show up in `ps`.
metrics=$(printf 'user = ":%s"\n' "$KUMA_API_KEY" \
  | /usr/bin/curl -fsS --max-time 15 -K - "$KUMA_URL/metrics") \
  || show_error "Can't reach Uptime Kuma"

# Output records:  S <ok> <total>  |  D <name>
# monitor_status values: 0 down, 1 up, 2 pending, 3 maintenance.
records=$(printf '%s\n' "$metrics" | /usr/bin/awk '
  BEGIN { OFS = "\t" }
  /^monitor_status\{/ {
    if (!match($0, /monitor_name="([^"\\]|\\.)*"/)) next
    name = substr($0, RSTART + 14, RLENGTH - 15)
    gsub(/\\"/, "\"", name)
    gsub(/\\\\/, "\\", name)
    if (name in seen) next
    seen[name] = 1
    value = $0
    sub(/.*[ \t]/, "", value)
    total++
    if (value + 0 != 0) ok++
    else print "D", name
  }
  END { print "S", ok + 0, total + 0 }
')

read -r _ ok total <<< "$(grep '^S' <<< "$records")"
down_rows=$(grep '^D' <<< "$records" | cut -f 2- | sort -f)

[ "$total" -gt 0 ] || show_error "No monitors found"

if [ -z "$down_rows" ]; then
  "$TW" --target $TW_TARGET \
    --icon checkmark.circle.fill \
    --text "$ok/$total OK" \
    --fit-text \
    --timestamp \
    --action-kind open-url --action-value "$KUMA_URL/dashboard" \
    --bg "$OK_BG" \
    --fg "$FG"
else
  # One-column table as JSON; TSV/CSV detection needs a tab or comma.
  printf '%s\n' "$down_rows" \
  | /usr/bin/jq -Rn '[["Down"]] + [inputs | [.]]' \
  | "$TW" --target $TW_TARGET \
      --table - \
      --grid zebra-row \
      --table-layout fill \
      --icon exclamationmark.triangle.fill \
      --text "$ok/$total OK" \
      --timestamp \
      --action-kind open-url --action-value "$KUMA_URL/dashboard" \
      --bg "$DOWN_BG" \
      --fg "$FG"
fi