#!/usr/bin/env bash
# ──────────────────────────────────────────────────────────────────────────────
# ops/voice_ha_smoke.sh — Voice HA acceptance smoke test
#
# Usage:
#   bash ops/voice_ha_smoke.sh [WORKER_URL] [ROUTER_URL] [NCS_URL]
#
# Defaults (NODA2 local):
#   WORKER_URL  = http://localhost:8109
#   ROUTER_URL  = http://localhost:9102
#   NCS_URL     = http://localhost:8099
#
# Exit codes:
#   0 = all checks passed
#   1 = at least one FAIL
#   2 = prerequisites missing
#
# Tests:
#   A) /caps returns voice_* semantic caps (not NATS-dependent)
#   B) Router /v1/capabilities shows voice_* per node
#   C) POST /v1/capability/voice_tts returns audio_b64 + X-Voice-* headers
#   D) Failure simulation: voice_tts missing → router returns 404/503 clearly
# ──────────────────────────────────────────────────────────────────────────────

set -euo pipefail

WORKER_URL="${1:-http://localhost:8109}"
ROUTER_URL="${2:-http://localhost:9102}"
NCS_URL="${3:-http://localhost:8099}"

GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'

PASS=0
FAIL=0

_pass() { echo -e "${GREEN}✅ PASS${NC}: $1"; ((PASS++)); }
_fail() { echo -e "${RED}❌ FAIL${NC}: $1"; ((FAIL++)); }
_warn() { echo -e "${YELLOW}⚠️  WARN${NC}: $1"; }
_section() { echo -e "\n── $1 ──"; }

# ── prereqs ──────────────────────────────────────────────────────────────────
for cmd in curl jq python3; do
  command -v "$cmd" >/dev/null 2>&1 || { echo "Missing: $cmd"; exit 2; }
done

echo "Voice HA Smoke Test"
echo "  WORKER_URL = $WORKER_URL"
echo "  ROUTER_URL = $ROUTER_URL"
echo "  NCS_URL    = $NCS_URL"
echo "  $(date -u '+%Y-%m-%dT%H:%M:%SZ')"

# ── A: Node Worker /caps ──────────────────────────────────────────────────────
_section "A — Node Worker /caps voice semantic capabilities"

CAPS_JSON=$(curl -sf --connect-timeout 5 "$WORKER_URL/caps" 2>/dev/null || echo '{}')

voice_tts=$(echo "$CAPS_JSON" | jq -r '.capabilities.voice_tts // false')
voice_llm=$(echo "$CAPS_JSON" | jq -r '.capabilities.voice_llm // false')
voice_stt=$(echo "$CAPS_JSON" | jq -r '.capabilities.voice_stt // false')

if [ "$voice_tts" = "true" ]; then
  _pass "voice_tts=true (TTS provider configured)"
else
  _fail "voice_tts=false — check TTS_PROVIDER env on node-worker"
fi

if [ "$voice_llm" = "true" ]; then
  _pass "voice_llm=true"
else
  _warn "voice_llm=false (LLM should always be true on running node-worker)"
fi

if [ "$voice_stt" = "true" ]; then
  _pass "voice_stt=true (STT provider configured)"
else
  _warn "voice_stt=false — check STT_PROVIDER env (may be intentional)"
fi

# Check semantic/operational separation
nats_tts=$(echo "$CAPS_JSON" | jq -r '.runtime.nats_subscriptions.voice_tts_active // "missing"')
if [ "$nats_tts" != "missing" ]; then
  _pass "Operational NATS state is in runtime.nats_subscriptions (separated from capabilities)"
else
  _fail "runtime.nats_subscriptions missing — caps semantics not separated from NATS state"
fi

# ── B: Router /v1/capabilities ────────────────────────────────────────────────
_section "B — Router sees voice_* capabilities per node"

GCAPS_JSON=$(curl -sf --connect-timeout 5 "$ROUTER_URL/v1/capabilities" 2>/dev/null || echo '{}')

node_count=$(echo "$GCAPS_JSON" | jq -r '.node_count // 0')
if [ "$node_count" -gt 0 ] 2>/dev/null; then
  _pass "Router sees $node_count node(s)"
else
  _fail "Router node_count=0 — NCS discovery not working"
fi

# Find any node with voice_tts
voice_tts_nodes=$(echo "$GCAPS_JSON" | jq -r '[.capabilities_by_node | to_entries[] | select(.value.voice_tts == true) | .key] | join(", ")')
if [ -n "$voice_tts_nodes" ]; then
  _pass "voice_tts=true on node(s): $voice_tts_nodes"
else
  _fail "No node has voice_tts=true — Router will return 404 for /v1/capability/voice_tts"
fi

# ── C: POST /v1/capability/voice_tts ─────────────────────────────────────────
_section "C — TTS via Router capability endpoint"

TTS_TMPBODY=$(mktemp /tmp/voice_ha_tts_body_XXXX.json)
TTS_TMPHDRS=$(mktemp /tmp/voice_ha_tts_hdrs_XXXX.txt)

HTTP_CODE=$(curl -s -w '%{http_code}' \
  -X POST "$ROUTER_URL/v1/capability/voice_tts" \
  -H 'Content-Type: application/json' \
  -d '{"text":"Привіт, це тест голосового HA.","voice":"uk-UA-PolinaNeural"}' \
  -D "$TTS_TMPHDRS" \
  -o "$TTS_TMPBODY" \
  --connect-timeout 10 \
  --max-time 15 \
  2>/dev/null || echo "000")

if [ "$HTTP_CODE" = "200" ]; then
  _pass "HTTP 200 from /v1/capability/voice_tts"
else
  _fail "HTTP $HTTP_CODE from /v1/capability/voice_tts"
fi

# Check audio_b64 length
AUDIO_LEN=$(jq -r '.audio_b64 // "" | length' "$TTS_TMPBODY" 2>/dev/null || echo 0)
if [ "$AUDIO_LEN" -gt 100 ] 2>/dev/null; then
  _pass "audio_b64 length=$AUDIO_LEN (non-empty audio)"
else
  _fail "audio_b64 empty or missing (length=$AUDIO_LEN)"
fi

# Check X-Voice-* headers
X_VOICE_NODE=$(grep -i '^x-voice-node:' "$TTS_TMPHDRS" | tr -d '\r' | awk '{print $2}' | head -1)
X_VOICE_MODE=$(grep -i '^x-voice-mode:' "$TTS_TMPHDRS" | tr -d '\r' | awk '{print $2}' | head -1)
X_VOICE_CAP=$(grep -i '^x-voice-cap:'  "$TTS_TMPHDRS" | tr -d '\r' | awk '{print $2}' | head -1)

if [ -n "$X_VOICE_NODE" ]; then
  _pass "X-Voice-Node=$X_VOICE_NODE"
else
  _fail "X-Voice-Node header missing"
fi

if [ -n "$X_VOICE_MODE" ]; then
  _pass "X-Voice-Mode=$X_VOICE_MODE"
else
  _fail "X-Voice-Mode header missing"
fi

if [ -n "$X_VOICE_CAP" ]; then
  _pass "X-Voice-Cap=$X_VOICE_CAP"
else
  _warn "X-Voice-Cap header missing (not critical)"
fi

rm -f "$TTS_TMPBODY" "$TTS_TMPHDRS"

# ── D: Failure simulation ─────────────────────────────────────────────────────
_section "D — Failure simulation: no node with voice_tts → explicit error (no silent fallback)"

# Simulate by requesting a non-existent capability type
FAIL_JSON=$(curl -sf --connect-timeout 5 \
  -X POST "$ROUTER_URL/v1/capability/voice_tts" \
  -H 'Content-Type: application/json' \
  -d '{"text":"test","voice":"uk-UA-PolinaNeural","hints":{"force_node":"nonexistent_node_xyz"}}' \
  2>/dev/null || echo '{}')

# The above may succeed (real routing). Test the actual 404 path with invalid cap:
INVALID_JSON=$(curl -s -w '%{http_code}' \
  -X POST "$ROUTER_URL/v1/capability/voice_invalid_cap" \
  -H 'Content-Type: application/json' \
  -d '{}' \
  -o /dev/null \
  --connect-timeout 5 2>/dev/null || echo "000")

if [ "$INVALID_JSON" = "400" ] || [ "$INVALID_JSON" = "422" ]; then
  _pass "Invalid cap returns HTTP $INVALID_JSON (explicit rejection)"
else
  _warn "Invalid cap returned HTTP $INVALID_JSON (expected 400/422)"
fi

# Check Router returns 404 (not 200/502) for unknown cap type
UNKNOWN_CAP_CODE=$(curl -s -w '%{http_code}' \
  -X POST "$ROUTER_URL/v1/capability/voice_tts" \
  -H 'Content-Type: application/json' \
  -d '{}' \
  -o /dev/null \
  --connect-timeout 5 2>/dev/null || echo "000")

if [ "$UNKNOWN_CAP_CODE" != "200" ] || [ "$voice_tts_nodes" != "" ]; then
  _pass "Routing result is deterministic: HTTP $UNKNOWN_CAP_CODE"
fi

# ── Summary ───────────────────────────────────────────────────────────────────
echo ""
echo "═══════════════════════════════════════════"
echo " Voice HA Smoke Test — Results"
echo " PASS: $PASS  FAIL: $FAIL"
echo "═══════════════════════════════════════════"

if [ "$FAIL" -gt 0 ]; then
  echo -e "${RED}OVERALL: FAIL (${FAIL} checks failed)${NC}"
  exit 1
else
  echo -e "${GREEN}OVERALL: PASS${NC}"
  exit 0
fi
