#!/usr/bin/env bash
# Check the mesh is actually meshed, and that the four identities are distinct.
#
#   ./mesh/verify.sh
#
# A broken mesh does not announce itself. Every node comes up healthy with zero
# peers if the shared peer key is wrong, and bills nobody at all if a key is
# missing -- both look like success in `compose ps`. Each check below is here
# because its failure mode is silent.
set -uo pipefail

MESH_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COMPOSE="docker compose -f $MESH_DIR/compose.yaml"
PORTS=(19001 19002 19003 19004)
fail=0

note() { printf '\n== %s\n' "$1"; }
bad()  { printf '   FAIL: %s\n' "$1"; fail=1; }
ok()   { printf '   ok: %s\n' "$1"; }

note "1. all four brokers answer"
for p in "${PORTS[@]}"; do
  if curl -fsS --max-time 5 "http://localhost:$p/health" >/dev/null 2>&1; then
    ok "localhost:$p"
  else
    bad "localhost:$p not answering /health"
  fi
done

note "2. the ring agrees (total must be 4, indices a permutation of 0..3)"
# Every broker sorts the same address list and hashes each username into it, so
# a disagreement here means two nodes think different people own the same
# credits -- the one failure that corrupts balances rather than just routing.
ring=$($COMPOSE logs --no-log-prefix 2>/dev/null | grep -o 'index=[0-9]*/[0-9]*' | sort -u)
totals=$(echo "$ring" | sed 's|.*/||' | sort -u)
indices=$(echo "$ring" | sed 's|index=||;s|/.*||' | sort -n | tr '\n' ' ')
if [ "$totals" = "4" ] && [ "$indices" = "0 1 2 3 " ]; then
  ok "index set {$indices} of 4"
else
  bad "ring disagreement: totals={$totals} indices={$indices}"
  echo "        (expected totals=4, indices='0 1 2 3')"
fi

note "3. every node sees all four workers"
# Its own, plus three learned over /peer/workers. Fewer than 4 means peering
# failed; the usual cause is a mismatched ZAKURO_PEER_KEY, which 401s every
# probe without logging an error.
for p in "${PORTS[@]}"; do
  n=$(curl -fsS --max-time 5 "http://localhost:$p/workers" 2>/dev/null |
      python3 -c 'import json,sys; print(json.load(sys.stdin).get("total","?"))' 2>/dev/null)
  if [ "$n" = "4" ]; then ok "localhost:$p sees 4"; else bad "localhost:$p sees ${n:-none}, want 4"; fi
done

note "4. the four nodes carry four DIFFERENT owner keys"
# The check that matters most. A copy-paste slip that gives two nodes the same
# key is invisible at runtime: both nodes work, and the earnings of one silently
# land in the other's account.
keys=$(for s in node1 node2 node3 node4; do
  $COMPOSE exec -T "$s" printenv ZAKURO_API_KEY 2>/dev/null
done)
distinct=$(echo "$keys" | grep -c . )
unique=$(echo "$keys" | sort -u | grep -c . )
if [ "$distinct" = "4" ] && [ "$unique" = "4" ]; then
  ok "4 keys, 4 distinct billing ids: $(echo "$keys" | cut -d_ -f2 | tr '\n' ' ')"
else
  bad "$distinct keys present, only $unique distinct"
fi

note "5. no node fell back to master-key billing"
# ZAKURO_MASTER_KEY resolves every caller to "admin", collapsing the four
# identities into one while the mesh keeps working perfectly.
for s in node1 node2 node3 node4; do
  v=$($COMPOSE exec -T "$s" printenv ZAKURO_MASTER_KEY 2>/dev/null || true)
  if [ -z "$v" ]; then ok "$s: unset"; else bad "$s: ZAKURO_MASTER_KEY is set"; fi
done

printf '\n'
if [ "$fail" = 0 ]; then
  echo "mesh verified: 4 nodes, 4 owners, one ring."
else
  echo "mesh NOT verified -- see FAILs above."
fi
exit "$fail"
