#!/bin/bash
# ============================================================================
# BTX Node Guardian, one command install.
#
#   Keeps your BTX node from getting quietly stuck, and tells you the truth
#   about why it stopped when it stops.
#
# What this does, in plain words:
#   - finds your node and your btx-cli for you
#   - installs one small script
#   - runs it every 5 minutes, automatically, including after a reboot
#   - shows you your node's health straight away
#
# It never restarts your node, never touches your data or keys, and it can be
# removed with one command that this installer prints at the end.
#
# Run it:   ./install-node-guardian.sh
# ============================================================================
set -u

say()  { printf '\n\033[1m%s\033[0m\n' "$*"; }
ok()   { printf '  \033[32m%s\033[0m\n' "$*"; }
warn() { printf '  \033[33m%s\033[0m\n' "$*"; }
die()  { printf '\n\033[31m%s\033[0m\n' "$*" >&2; exit 1; }

# Served from easybtx.com, NOT from raw.githubusercontent.com: the source repo is
# private, so the raw URL 404s for everyone outside the org. A tester hit exactly
# that within a day of this going out. Override with GUARDIAN_URL if you mirror it.
RAW="${GUARDIAN_URL:-https://easybtx.com/btx-node-guardian.sh}"
HOME_DIR="${HOME:?}"
DEST="$HOME_DIR/.btx-guardian"
SCRIPT="$DEST/btx-node-guardian.sh"

say "BTX Node Guardian"
command -v python3 >/dev/null || die "python3 is required (it reads your node's JSON). Install python3 and run this again."
command -v curl >/dev/null || die "curl is required. Install curl and run this again."

# ── 1. Find btx-cli ─────────────────────────────────────────────────────────
say "1/4  Looking for your node"
CLI="${BTX_CLI:-}"
if [ -z "$CLI" ]; then
    for c in "$(command -v btx-cli 2>/dev/null)" \
             "$HOME_DIR/.btx-keeper/bin/btx-cli" \
             /usr/local/bin/btx-cli /usr/bin/btx-cli \
             /data/src/*/build/bin/btx-cli "$HOME_DIR"/*/bin/btx-cli; do
        [ -n "${c:-}" ] && [ -x "$c" ] && { CLI="$c"; break; }
    done
fi
# last resort: ask the running process where it came from
if [ -z "$CLI" ]; then
    p=$(pgrep -f '[b]txd' | head -1)
    [ -n "$p" ] && [ -r "/proc/$p/exe" ] && {
        d=$(dirname "$(readlink -f "/proc/$p/exe")"); [ -x "$d/btx-cli" ] && CLI="$d/btx-cli"; }
fi
[ -n "$CLI" ] || die "Could not find btx-cli. Run again with its path, like this:
    BTX_CLI=/path/to/btx-cli ./install-node-guardian.sh"
ok "btx-cli: $CLI"

# ── 2. Find the datadir ─────────────────────────────────────────────────────
DATADIR="${BTX_DATADIR:-}"
if [ -z "$DATADIR" ]; then
    # a running node tells us exactly, no guessing
    args=$(ps -o args= -p "$(pgrep -f '[b]txd' | head -1)" 2>/dev/null || true)
    case "$args" in *-datadir=*) DATADIR="${args##*-datadir=}"; DATADIR="${DATADIR%% *}";; esac
fi
if [ -z "$DATADIR" ]; then
    for d in "$HOME_DIR/.btx" "$HOME_DIR/.btx-keeper" /data/btx "$HOME_DIR/.easybtx"; do
        [ -d "$d" ] && { DATADIR="$d"; break; }
    done
fi
[ -n "$DATADIR" ] || die "Could not find your node's data folder. Run again with it, like this:
    BTX_DATADIR=/path/to/datadir ./install-node-guardian.sh"
ok "data folder: $DATADIR"

# prove the pair actually works before installing anything
if ! "$CLI" -datadir="$DATADIR" getblockcount >/dev/null 2>&1; then
    die "Found btx-cli and a data folder, but the node did not answer.
Is it running? Try:  $CLI -datadir=$DATADIR getblockcount"
fi
ok "your node answered, height $("$CLI" -datadir="$DATADIR" getblockcount 2>/dev/null)"

# ── 3. Install ──────────────────────────────────────────────────────────────
say "2/4  Installing"
mkdir -p "$DEST"
curl -fsSL -o "$SCRIPT.new" "$RAW" || die "Download failed. Check the machine can reach github.com."
head -1 "$SCRIPT.new" | grep -q '^#!/bin/bash' || die "That download does not look right. Nothing was installed."
mv -f "$SCRIPT.new" "$SCRIPT"; chmod +x "$SCRIPT"
ok "installed to $SCRIPT"

# ── 4. Run it every 5 minutes ───────────────────────────────────────────────
say "3/4  Setting it to run every 5 minutes"
SCHED=""
if command -v systemctl >/dev/null 2>&1 && [ "$(id -u)" = 0 ]; then
    cat > /etc/systemd/system/btx-guardian.service <<UNIT
[Unit]
Description=BTX Node Guardian
After=network-online.target

[Service]
Type=oneshot
Environment=BTX_CLI=$CLI
Environment=BTX_DATADIR=$DATADIR
ExecStart=$SCRIPT
Nice=10
UNIT
    cat > /etc/systemd/system/btx-guardian.timer <<UNIT
[Unit]
Description=Run the BTX Node Guardian every 5 minutes

[Timer]
OnBootSec=3min
OnUnitActiveSec=5min
Persistent=true

[Install]
WantedBy=timers.target
UNIT
    systemctl daemon-reload && systemctl enable --now btx-guardian.timer >/dev/null 2>&1 \
        && { SCHED="systemd timer"; ok "systemd timer enabled, it survives reboots"; }
fi
if [ -z "$SCHED" ] && command -v crontab >/dev/null 2>&1; then
    line="*/5 * * * * BTX_CLI=$CLI BTX_DATADIR=$DATADIR $SCRIPT"
    ( crontab -l 2>/dev/null | grep -v 'btx-node-guardian.sh'; echo "$line" ) | crontab - \
        && { SCHED="cron"; ok "cron entry added"; }
fi
[ -n "$SCHED" ] || warn "Could not schedule it automatically. Run this yourself every few minutes:
    BTX_CLI=$CLI BTX_DATADIR=$DATADIR $SCRIPT"

# ── 5. First run ────────────────────────────────────────────────────────────
say "4/4  Checking your node now"
BTX_CLI="$CLI" BTX_DATADIR="$DATADIR" GUARDIAN_STATE="$DEST" \
  GUARDIAN_LOG="$DEST/guardian.log" GUARDIAN_BEACON="$DEST/health.json" "$SCRIPT"

if [ -r "$DEST/health.json" ]; then
    python3 - "$DEST/health.json" <<'PY'
import json,sys
d=json.load(open(sys.argv[1]))
v=d.get("verdict","?")
plain={
 "ok":"Everything looks fine.",
 "network_frontier_quiet":"Your node is fine. The whole network is waiting for the next signed block.",
 "no_qualifying_peer":"Your node has no peer allowed to send it signed confirmations. The Guardian is dialling them.",
 "attestation_missing":"Your node has the next block but not its signature yet. The Guardian is dialling the archives.",
 "body_missing":"Your node is behind and nobody is sending it blocks. The Guardian is dialling the archives.",
 "electrs_lagging":"Your node is fine, but the index behind it is falling behind.",
 "btxd_down":"Your node is not running.",
 "rpc_unreachable":"Your node is not answering.",
}.get(v, v)
print(f"\n  Your node: height {d.get('blocks')}, signed frontier {d.get('signed_frontier')}, "
      f"{d.get('peers')} peers")
print(f"  Verdict:   {plain}")
PY
fi

cat <<DONE

  Done. The Guardian now checks your node every 5 minutes.

  See your node's health:   cat ~/.btx-guardian/health.json
  See what it has done:     cat ~/.btx-guardian/guardian.log
  Remove it completely:     $( [ "$SCHED" = "systemd timer" ] && echo "sudo systemctl disable --now btx-guardian.timer && sudo rm /etc/systemd/system/btx-guardian.* && rm -rf ~/.btx-guardian" || echo "crontab -l | grep -v btx-node-guardian | crontab - && rm -rf ~/.btx-guardian" )

  It will never restart your node and never touches your keys or data.

DONE
