#!/usr/bin/env bash
# Live M3 smoke test. Run from repo root:
#   bash scripts/m3_smoke.sh
#
# Walks through the scenarios in M3_VERIFICATION.md:
#
#   Step 2 — warning to db-prod-04 → Alice only (Alice pre-linked, Bob not
#            yet linked, Carol unlinked + quiet hours).
#            Expected: 1 fcm (Alice) + 1 telegram (Alice).
#   Step 3 — critical to db-prod-04 → Alice + Bob (fcm). Bob is unlinked
#            so no telegram for him.
#   Step 4 — Bob runs /start acme-bob-002 via faketgmd admin queue.
#            Expect reply + telegram_user_id linked.
#   Step 5 — critical to db-prod-04 again. Bob is now linked.
#            Expected: 1 fcm (Alice) + 1 fcm (Bob) + 1 telegram (Alice) +
#            1 telegram (Bob).
#   Step 6 — inminent_colapse to rack-b. Carol's quiet hours (00:00-23:59
#            UTC) are bypassed. Bob is at min_severity=critical so he
#            passes. Expected: 1 fcm + 1 telegram for Alice, Bob, Carol
#            → 6 deliveries.
#   Step 7 — Bob /preferences. Confirm 1 subscription row, channel_mask
#            fcm+telegram, min=critical.
#   Step 8 — faketgmd /admin/sent should have 3 telegram messages
#            (one per Alice/Bob/Carol from step 6 plus 2 from step 5).
#
# Exit code is the number of failed checks.

set -e
cd "$(dirname "$0")/.."

SECRET=s3cret-acme
INGEST=http://localhost:8800/v1/ingest
TELEGRAM_BOT_TOKEN=fake-tg-bot-token-acme-001
FAKETGMD=http://localhost:8830
PG="docker exec -i broad-announce-postgres-1 psql -U ba -d ba -A -t"

send() {
  # send <body> <label> [var_out]
  # Echoes the response; if var_out is set, stores the alert_id in it.
  local body="$1" label="$2" var_out="$3"
  local ts=$(date +%s)
  local sig=$(printf '%s.%s' "$ts" "$body" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $2}')
  local resp
  resp=$(curl -s -X POST "$INGEST" \
    -H "Content-Type: application/json" \
    -H "X-BA-Signature: t=$ts,v1=$sig" \
    --data "$body")
  echo "[$label] $resp"
  if [[ -n "$var_out" ]]; then
    # alert_id is the first JSON string of the form "00000..."
    local aid
    aid=$(printf '%s' "$resp" | python3 -c 'import sys,json,re; s=sys.stdin.read(); m=re.search(r"\"alert_id\":\"([0-9a-f]+)\"", s); print(m.group(1) if m else "")')
    printf -v "$var_out" '%s' "$aid"
  fi
}

queue() {
  local text="$1" user_id="$2" chat_id="$3"
  curl -s -X POST "$FAKETGMD/admin/queue" \
    -H "Content-Type: application/json" \
    --data "$(cat <<JSON
{"bot_token":"$TELEGRAM_BOT_TOKEN","user_id":$user_id,"chat_id":$chat_id,"text":"$text","first_name":"Bob SRE"}
JSON
)"
  echo
}

fails=0
pass() { echo "  ✅ $*"; }
fail() { echo "  ❌ $*"; fails=$((fails+1)); }

echo "═══════════════════════════════════════════════════════"
echo "  M3 smoke test — broad-announce"
echo "═══════════════════════════════════════════════════════"

echo
echo "▸ Pre-flight: reset state and restart telegramd so its long-poll offset clears"
# Reset DB to M3 baseline: Bob unlinked, Bob subscription min=critical.
$PG -c "UPDATE individuals SET telegram_chat_id = NULL, telegram_user_id = NULL, telegram_invite_code = 'acme-bob-002' WHERE id = 'ind-acme-002';" >/dev/null
$PG -c "UPDATE individuals SET telegram_chat_id = NULL, telegram_user_id = NULL WHERE id = 'ind-acme-003';" >/dev/null
$PG -c "UPDATE subscriptions SET min_severity = 'critical' WHERE individual_id = 'ind-acme-002' AND source_id = 'prom-prod';" >/dev/null
$PG -c "TRUNCATE deliveries;" >/dev/null
# Reset faketgmd's queue + sent (and its in-memory per-bot offset).
curl -sS -X POST "$FAKETGMD/admin/reset" >/dev/null
# Restart telegramd so its in-process long-poll offset goes back to 0.
# (In production, Telegram's getUpdates tracks the offset server-side;
#  faketgmd is a fake that needs the bot to be re-started for clean state.)
docker compose restart telegramd >/dev/null
# Wait for telegramd to come up and load its bot list.
for i in 1 2 3 4 5 6 7 8 9 10; do
  if curl -sS http://localhost:8822/health 2>/dev/null | grep -q '"status":"ok"'; then
    sleep 1   # let it issue the first getUpdates long-poll
    break
  fi
  sleep 1
done

echo
echo "▸ Pre-flight: state"
echo "  individuals:"
$PG -c "SELECT id, telegram_chat_id, telegram_user_id, telegram_invite_code FROM individuals ORDER BY id;" | sed 's/^/    /'
echo "  subscriptions:"
$PG -c "SELECT individual_id, min_severity, channel_mask, status FROM subscriptions WHERE source_id='prom-prod' ORDER BY individual_id;" | sed 's/^/    /'
echo "  deliveries (should be 0):"
$PG -c "SELECT COUNT(*) FROM deliveries;" | sed 's/^/    /'
echo "  faketgmd sent (should be 0):"
curl -sS "$FAKETGMD/admin/sent" | sed 's/^/    /'
echo

# Helper: count rows in deliveries for a specific alert_id.
rows_for() {
  $PG -c "SELECT COUNT(*) FROM deliveries WHERE alert_id = '$1';"
}
rows_total() { $PG -c "SELECT COUNT(*) FROM deliveries;"; }
rows_channel() { $PG -c "SELECT COUNT(*) FROM deliveries WHERE channel='$1' AND status='sent';"; }
rows_channel_total() { $PG -c "SELECT COUNT(*) FROM deliveries WHERE channel='$1';"; }

# ── Step 2: warning → db-prod-04 → Alice only ─────────────────
echo "▸ Step 2: POST warning (Alice only; Bob unlinked; Carol quiet hours)"
send '{"company_id":"acme-001","source_id":"prom-prod","severity":"warning","category":"storage","title":"Disk 80% full","body":"db-prod-04","data":{"host":"db-prod-04"},"dedupe_key":"m3-s2"}' "step 2" aid2
sleep 4
n=$(rows_for "$aid2")
[[ "$n" == "2" ]] && pass "2 deliveries for step-2 alert (1 fcm + 1 telegram for Alice)" || fail "expected 2 deliveries for step 2, got $n"
fb=$(rows_channel fcm)
tb=$(rows_channel telegram)
[[ "$fb" == "1" && "$tb" == "1" ]] && pass "running totals: fcm=1, telegram=1" || fail "fcm=$fb, telegram=$tb (expected 1,1)"

# ── Step 3: critical → db-prod-04 → Alice + Bob (fcm only) ─────
echo
echo "▸ Step 3: POST critical (Bob unlinked, telegram skipped for him)"
send '{"company_id":"acme-001","source_id":"prom-prod","severity":"critical","category":"storage","title":"Disk full","body":"db-prod-04","data":{"host":"db-prod-04"},"dedupe_key":"m3-s3"}' "step 3" aid3
sleep 4
n=$(rows_for "$aid3")
[[ "$n" == "3" ]] && pass "3 deliveries for step-3 alert (Alice fcm+telegram, Bob fcm only)" || fail "expected 3 deliveries for step 3, got $n"
fb=$(rows_channel fcm)
tb=$(rows_channel telegram)
[[ "$fb" == "3" && "$tb" == "2" ]] && pass "running totals: fcm=3, telegram=2 (Bob telegram blocked by missing link, Alice has 1+1)" || fail "fcm=$fb, telegram=$tb (expected 3,2)"

# ── Step 4: Bob /start acme-bob-002 via faketgmd queue ─────────
echo
echo "▸ Step 4: Bob runs /start acme-bob-002"
queue "/start acme-bob-002" 900002 2002
sleep 4
linked=$($PG -c "SELECT telegram_user_id FROM individuals WHERE id = 'ind-acme-002';")
[[ "$linked" == "900002" ]] && pass "Bob linked (telegram_user_id=900002)" || fail "Bob telegram_user_id='$linked' (expected 900002)"
bot_reply=$(curl -sS "$FAKETGMD/admin/sent" | grep -c '"text":"Linked' || true)
[[ "$bot_reply" -ge 1 ]] && pass "faketgmd saw bot's 'Linked' reply" || fail "no 'Linked' reply from bot"

# ── Step 5: critical → db-prod-04 again; Bob telegram should now fire ─
echo
echo "▸ Step 5: POST critical (Bob now linked, telegram should fire for him)"
send '{"company_id":"acme-001","source_id":"prom-prod","severity":"critical","category":"storage","title":"Disk full","body":"db-prod-04","data":{"host":"db-prod-04"},"dedupe_key":"m3-s5"}' "step 5" aid5
sleep 4
n=$(rows_for "$aid5")
[[ "$n" == "4" ]] && pass "4 deliveries for step-5 alert (2 fcm + 2 telegram for Alice + Bob)" || fail "expected 4 deliveries for step 5, got $n"
fb=$(rows_channel fcm)
tb=$(rows_channel telegram)
[[ "$fb" == "5" && "$tb" == "4" ]] && pass "running totals: fcm=5, telegram=4 (Bob now receives telegram)" || fail "fcm=$fb, telegram=$tb (expected 5,4)"

# ── Step 6: inminent_colapse → all three via fcm, but Carol unlinked (no telegram) ─
echo
echo "▸ Step 6: POST inminent_colapse (Carol's quiet hours bypassed → fcm, but Carol unlinked → no telegram)"
send '{"company_id":"acme-001","source_id":"prom-prod","severity":"inminent_colapse","category":"power","title":"PDU overload imminent","body":"rack-B","data":{"host":"rack-b"},"dedupe_key":"m3-s6"}' "step 6" aid6
sleep 4
n=$(rows_for "$aid6")
[[ "$n" == "5" ]] && pass "5 deliveries for step-6 alert (3 fcm + 2 telegram: Alice, Bob fcm+telegram; Carol fcm only — never linked)" || fail "expected 5 deliveries for step 6, got $n"
fb=$(rows_channel fcm)
tb=$(rows_channel telegram)
[[ "$fb" == "8" && "$tb" == "6" ]] && pass "running totals: fcm=8, telegram=6" || fail "fcm=$fb, telegram=$tb (expected 8,6)"

# ── Step 7: Bob /preferences ────────────────────────────────────
echo
echo "▸ Step 7: Bob runs /preferences"
queue "/preferences" 900002 2002
sleep 3
prefs=$(curl -sS "$FAKETGMD/admin/sent" | grep -c '"text":"Your subscriptions' || true)
[[ "$prefs" -ge 1 ]] && pass "faketgmd saw bot's preferences reply" || fail "no preferences reply from bot"

# ── Step 8: faketgmd sent count ─────────────────────────────────
echo
echo "▸ Step 8: faketgmd totals"
sent=$(curl -sS "$FAKETGMD/admin/sent" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d["count"])')
[[ "$sent" -ge 5 ]] && pass "faketgmd received $sent sendMessage calls (>=5 expected: 1 alice/step2 + 1 alice/step3 + 1 linked-reply + 1 alice/step5 + 1 bob/step5 + 3 step6 + 1 prefs-reply = 8)" || fail "faketgmd sent count=$sent, expected >=5"

echo
echo "═══════════════════════════════════════════════════════"
echo "  Per-individual / per-channel delivery table"
echo "═══════════════════════════════════════════════════════"
$PG -c "SELECT individual_id, channel, status, COUNT(*) AS n FROM deliveries GROUP BY 1,2,3 ORDER BY 1,2;" | sed 's/^/  /'

echo
if [[ "$fails" -eq 0 ]]; then
  echo "✅  M3 smoke: 0 failures"
  exit 0
else
  echo "❌  M3 smoke: $fails failure(s)"
  exit $fails
fi
