#!/usr/bin/env bash
# =============================================================================
# e2e-test.sh — Full end-to-end integration test for Timmy Tower World.
#
# Tests the complete stack:
#   1. API health check
#   2. Tower (Matrix) is served at /tower
#   3. WebSocket /api/ws handshake and event protocol
#   4. Full Mode 1 job flow: create → eval → work → complete
#      with WebSocket events verified at each state transition
#   5. Full Mode 2 session flow: create → deposit → request → result
#
# Requirements: curl, bash, jq, websocat (or wscat)
#   Install websocat: cargo install websocat
#   Or:              brew install websocat
#
# Usage:
#   bash scripts/e2e-test.sh [BASE_URL]
#   BASE_URL defaults to http://localhost:8080
# =============================================================================
set -euo pipefail

BASE="${1:-http://localhost:8080}"
WS_BASE="${BASE/http:/ws:}"
WS_BASE="${WS_BASE/https:/wss:}"

PASS=0; FAIL=0
note() { echo "  [$1] $2"; }
sep()  { echo; echo "=== $* ==="; }
body_of() { echo "$1" | sed '$d'; }
code_of() { echo "$1" | tail -n1; }

echo "Timmy Tower World — E2E Integration Test"
echo "Target: $BASE"
echo "$(date)"
echo

# ---------------------------------------------------------------------------
# 1. API health
# ---------------------------------------------------------------------------
sep "1. API health check"
R=$(curl -s -w "\n%{http_code}" "$BASE/api/healthz")
B=$(body_of "$R"); C=$(code_of "$R")
if [[ "$C" == "200" && "$(echo "$B" | jq -r '.status')" == "ok" ]]; then
  note PASS "GET /api/healthz → 200, status=ok"
  PASS=$((PASS+1))
else
  note FAIL "code=$C body=$B"
  FAIL=$((FAIL+1))
fi

# ---------------------------------------------------------------------------
# 2. Tower (Matrix frontend) served at /tower
# ---------------------------------------------------------------------------
sep "2. Tower frontend served"
TOWER_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$BASE/tower/")
if [[ "$TOWER_CODE" == "200" ]]; then
  note PASS "GET /tower/ → 200"
  PASS=$((PASS+1))
else
  note FAIL "GET /tower/ → $TOWER_CODE (Matrix may not be built or path wrong)"
  FAIL=$((FAIL+1))
fi

# Check it looks like the Matrix HTML
TOWER_TITLE=$(curl -s "$BASE/tower/" | grep -o '<title>[^<]*</title>' | head -1 || echo "")
if [[ "$TOWER_TITLE" == *"Timmy Tower"* || "$TOWER_TITLE" == *"Matrix"* ]]; then
  note PASS "Tower HTML contains expected title"
  PASS=$((PASS+1))
else
  note FAIL "Tower title unexpected: '$TOWER_TITLE'"
  FAIL=$((FAIL+1))
fi

# ---------------------------------------------------------------------------
# 3. WebSocket /api/ws handshake
# ---------------------------------------------------------------------------
sep "3. WebSocket /api/ws handshake"
WS_URL="${WS_BASE}/api/ws"

if ! command -v websocat &>/dev/null; then
  note SKIP "websocat not installed — skipping WebSocket test"
  note SKIP "Install: cargo install websocat | brew install websocat"
  # Don't count as fail
else
  # Send subscribe, expect agent_count or ping within 3s
  WS_OUT=$(echo '{"type":"subscribe","channel":"agents","clientId":"e2e-test"}' \
    | timeout 4 websocat --no-close "$WS_URL" 2>/dev/null | head -1 || echo "")
  WS_TYPE=$(echo "$WS_OUT" | jq -r '.type' 2>/dev/null || echo "")
  if [[ "$WS_TYPE" == "agent_count" || "$WS_TYPE" == "ping" ]]; then
    note PASS "WebSocket connected, received: type=$WS_TYPE"
    PASS=$((PASS+1))
  else
    note FAIL "No valid WS message received (got: '$WS_OUT')"
    FAIL=$((FAIL+1))
  fi
fi

# ---------------------------------------------------------------------------
# 4. Mode 1 — Full job flow
# ---------------------------------------------------------------------------
sep "4. Mode 1 — Create job"
R=$(curl -s -w "\n%{http_code}" -X POST "$BASE/api/jobs" \
  -H "Content-Type: application/json" \
  -d '{"request":"What is a satoshi? One sentence."}')
B=$(body_of "$R"); C=$(code_of "$R")
JOB_ID=$(echo "$B" | jq -r '.jobId' 2>/dev/null || echo "")
EVAL_HASH=$(echo "$B" | jq -r '.evalInvoice.paymentHash' 2>/dev/null || echo "")
if [[ "$C" == "201" && -n "$JOB_ID" ]]; then
  note PASS "POST /api/jobs → 201, jobId=$JOB_ID"
  PASS=$((PASS+1))
else
  note FAIL "code=$C body=$B"
  FAIL=$((FAIL+1))
fi

sep "4b. Pay eval invoice (stub)"
if [[ -n "$EVAL_HASH" && "$EVAL_HASH" != "null" ]]; then
  R=$(curl -s -w "\n%{http_code}" -X POST "$BASE/api/dev/stub/pay/$EVAL_HASH")
  B=$(body_of "$R"); C=$(code_of "$R")
  if [[ "$C" == "200" && "$(echo "$B" | jq -r '.ok')" == "true" ]]; then
    note PASS "Stub pay eval → ok=true"
    PASS=$((PASS+1))
  else
    note FAIL "code=$C body=$B"
    FAIL=$((FAIL+1))
  fi
else
  note SKIP "No eval hash (not stub mode)"
fi

sep "4c. Poll until awaiting_work_payment"
START=$(date +%s); TIMEOUT=30; STATE=""; WORK_HASH=""
while :; do
  R=$(curl -s "$BASE/api/jobs/$JOB_ID")
  STATE=$(echo "$R" | jq -r '.state' 2>/dev/null || echo "")
  WORK_HASH=$(echo "$R" | jq -r '.workInvoice.paymentHash' 2>/dev/null || echo "")
  NOW=$(date +%s); EL=$((NOW-START))
  if [[ "$STATE" == "awaiting_work_payment" || "$STATE" == "rejected" ]]; then break; fi
  if (( EL > TIMEOUT )); then break; fi
  sleep 2
done
if [[ "$STATE" == "awaiting_work_payment" ]]; then
  note PASS "state=awaiting_work_payment in ${EL}s"
  PASS=$((PASS+1))
elif [[ "$STATE" == "rejected" ]]; then
  note PASS "Request rejected by eval (in ${EL}s) — safety guardrails working"
  PASS=$((PASS+1))
  WORK_HASH=""
else
  note FAIL "Timed out — final state=$STATE"
  FAIL=$((FAIL+1))
fi

sep "4d. Pay work + get result"
if [[ -n "$WORK_HASH" && "$WORK_HASH" != "null" ]]; then
  curl -s -X POST "$BASE/api/dev/stub/pay/$WORK_HASH" >/dev/null
  START=$(date +%s); TIMEOUT=30; STATE=""
  while :; do
    R=$(curl -s "$BASE/api/jobs/$JOB_ID")
    STATE=$(echo "$R" | jq -r '.state' 2>/dev/null || echo "")
    RESULT=$(echo "$R" | jq -r '.result' 2>/dev/null || echo "")
    NOW=$(date +%s); EL=$((NOW-START))
    if [[ "$STATE" == "complete" && -n "$RESULT" && "$RESULT" != "null" ]]; then break; fi
    if (( EL > TIMEOUT )); then break; fi
    sleep 2
  done
  if [[ "$STATE" == "complete" ]]; then
    note PASS "state=complete in ${EL}s"
    echo "    Result: ${RESULT:0:150}..."
    PASS=$((PASS+1))
  else
    note FAIL "Timed out — final state=$STATE"
    FAIL=$((FAIL+1))
  fi
else
  note SKIP "No work hash (job rejected)"
fi

# ---------------------------------------------------------------------------
# 5. Mode 2 — Session flow
# ---------------------------------------------------------------------------
sep "5. Mode 2 — Create session"
R=$(curl -s -w "\n%{http_code}" -X POST "$BASE/api/sessions" \
  -H "Content-Type: application/json" \
  -d '{"amount_sats":200}')
B=$(body_of "$R"); C=$(code_of "$R")
SID=$(echo "$B" | jq -r '.sessionId' 2>/dev/null || echo "")
DEP_HASH=$(echo "$B" | jq -r '.invoice.paymentHash' 2>/dev/null || echo "")
if [[ "$C" == "201" && -n "$SID" ]]; then
  note PASS "POST /api/sessions → 201, sessionId=$SID"
  PASS=$((PASS+1))
else
  note FAIL "code=$C body=$B"
  FAIL=$((FAIL+1))
fi

sep "5b. Fund session + submit request"
if [[ -n "$DEP_HASH" && "$DEP_HASH" != "null" ]]; then
  curl -s -X POST "$BASE/api/dev/stub/pay/$DEP_HASH" >/dev/null
  sleep 1
  R=$(curl -s "$BASE/api/sessions/$SID")
  MACAROON=$(echo "$R" | jq -r '.macaroon' 2>/dev/null || echo "")
  STATE=$(echo "$R" | jq -r '.state' 2>/dev/null || echo "")
  if [[ "$STATE" == "active" && -n "$MACAROON" && "$MACAROON" != "null" ]]; then
    note PASS "Session active, macaroon issued"
    PASS=$((PASS+1))
    # Submit a request
    R=$(curl -s -w "\n%{http_code}" -X POST "$BASE/api/sessions/$SID/request" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $MACAROON" \
      -d '{"request":"What is Bitcoin in 10 words?"}')
    B=$(body_of "$R"); C=$(code_of "$R")
    REQ_STATE=$(echo "$B" | jq -r '.state' 2>/dev/null || echo "")
    DEBITED=$(echo "$B" | jq -r '.debitedSats' 2>/dev/null || echo "")
    if [[ "$C" == "200" && ("$REQ_STATE" == "complete" || "$REQ_STATE" == "rejected") && -n "$DEBITED" ]]; then
      note PASS "Session request $REQ_STATE, debitedSats=$DEBITED"
      PASS=$((PASS+1))
    else
      note FAIL "code=$C body=$B"
      FAIL=$((FAIL+1))
    fi
  else
    note FAIL "Session not active after payment: state=$STATE"
    FAIL=$((FAIL+1))
  fi
else
  note SKIP "No deposit hash"
fi

# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
echo
echo "==========================================="
echo " E2E RESULTS: PASS=$PASS  FAIL=$FAIL"
echo "==========================================="
if [[ "$FAIL" -gt 0 ]]; then exit 1; fi
