#!/usr/bin/env bash
# FFAI Agent 端到端 smoke 脚本 ——
# 对真实 backend（默认 localhost:4201，可用 API_BASE 覆盖）跑一遍：
#   ① login → ② resolve org → ③ 建 persona（带 instructions）→
#   ④ 建 session 绑 persona → ⑤ 用户写一条 USER memory → ⑥ admin 加 ORG memory →
#   ⑦ runTurn 发消息含 <remember> → ⑧ 验证 ASSISTANT_TEXT 已剥离 tag + memory 落表 +
#      memoriesAutoCreated=N + ai-detected source
#
# 目的：验证 Memory 三维度 + auto-extract + persona.instructions 注入端到端通；
# 提供给 CI / 人工 demo / 部署后冒烟。
#
# 用法：
#   bash scripts/agent-smoke.sh                 # 默认 localhost:4201 / itadmin
#   API_BASE=http://localhost:4201 bash ...     # 自定义 base
#   API_USER=itadmin API_PASS=Admin@2024 ...    # 自定义凭据
#   VERBOSE=1 bash scripts/agent-smoke.sh       # 打印每一步响应

set -euo pipefail

API_BASE="${API_BASE:-http://localhost:4201/api/v1}"
API_USER="${API_USER:-itadmin}"
API_PASS="${API_PASS:-Admin@2024}"
VERBOSE="${VERBOSE:-0}"

step() { echo ""; echo "▶ $*"; }
fail() { echo "❌ $*" >&2; exit 1; }
ok()   { echo "✅ $*"; }

dump() {
  if [[ "$VERBOSE" == "1" ]]; then
    echo "$1" | python3 -m json.tool 2>/dev/null || echo "$1"
  fi
}

# 不显示密码到 set -x
{ set +x; } 2>/dev/null

step "① POST /auth/login"
LOGIN=$(curl -sk -X POST "$API_BASE/auth/login" -H 'Content-Type: application/json' \
  -d "{\"username\":\"$API_USER\",\"password\":\"$API_PASS\"}")
dump "$LOGIN"
TOKEN=$(echo "$LOGIN" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['accessToken'])")
[[ -z "$TOKEN" ]] && fail "login failed: $LOGIN"
ok "token acquired (len=${#TOKEN})"

step "② GET /organizations 拿 org 上下文"
ORG_RESP=$(curl -sk "$API_BASE/organizations" -H "Authorization: Bearer $TOKEN")
dump "$ORG_RESP"
ORG=$(echo "$ORG_RESP" | python3 -c "import sys,json;d=json.load(sys.stdin);items=d['data'].get('items') or d['data'];print(items[0]['id'])")
[[ -z "$ORG" ]] && fail "no organization available — run db:seed (含 default org)"
ok "org=$ORG"

HDR=(-H "Authorization: Bearer $TOKEN" -H "X-Organization-Id: $ORG" -H 'Content-Type: application/json')

step "③ POST /agent/personas 建带 instructions 的 persona"
PERSONA=$(curl -sk -X POST "$API_BASE/agent/personas" "${HDR[@]}" \
  -d '{"name":"SmokeTester","instructions":"你是 smoke 测试用例 agent，只回 SMOKE_OK"}')
dump "$PERSONA"
PERSONA_ID=$(echo "$PERSONA" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['id'])")
[[ -z "$PERSONA_ID" ]] && fail "persona create failed"
ok "persona=$PERSONA_ID"

step "④ POST /agent/sessions 绑 persona"
SESS=$(curl -sk -X POST "$API_BASE/agent/sessions" "${HDR[@]}" \
  -d "{\"title\":\"smoke-test\",\"personaId\":\"$PERSONA_ID\"}")
dump "$SESS"
SESS_ID=$(echo "$SESS" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['id'])")
[[ -z "$SESS_ID" ]] && fail "session create failed"
SESS_PERSONA=$(echo "$SESS" | python3 -c "import sys,json;print(json.load(sys.stdin)['data'].get('personaId',''))")
[[ "$SESS_PERSONA" != "$PERSONA_ID" ]] && fail "session.personaId mismatch ($SESS_PERSONA vs $PERSONA_ID)"
ok "session=$SESS_ID with personaId bound"

step "⑤ POST /agent/memories 写一条 user 私有 memory"
MEM=$(curl -sk -X POST "$API_BASE/agent/memories" "${HDR[@]}" \
  -d '{"content":"smoke: user prefers concise replies","category":"USER"}')
dump "$MEM"
MEM_ID=$(echo "$MEM" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['id'])")
[[ -z "$MEM_ID" ]] && fail "memory create failed"
ok "user-memory=$MEM_ID"

step "⑥ POST /agent/admin/memories 加 ORG-shared memory"
ORG_MEM=$(curl -sk -X POST "$API_BASE/agent/admin/memories" "${HDR[@]}" \
  -d '{"content":"smoke: org policy — all amounts in CNY","category":"PROJECT"}')
dump "$ORG_MEM"
ORG_MEM_ID=$(echo "$ORG_MEM" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['id'])")
[[ -z "$ORG_MEM_ID" ]] && fail "org memory create failed (admin role missing?)"
ORG_MEM_OWNER=$(echo "$ORG_MEM" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['ownerScope'])")
[[ "$ORG_MEM_OWNER" != "ORG" ]] && fail "ownerScope should be ORG, got $ORG_MEM_OWNER"
ok "org-memory=$ORG_MEM_ID (ownerScope=ORG)"

step "⑦ POST /agent/messages 发一条消息（mock provider 走完整 LLM pipeline）"
MSG=$(curl -sk -X POST "$API_BASE/agent/messages" "${HDR[@]}" \
  -d "{\"sessionId\":\"$SESS_ID\",\"prompt\":\"smoke\"}")
dump "$MSG"
OK=$(echo "$MSG" | python3 -c "import sys,json;print(json.load(sys.stdin).get('success',False))")
[[ "$OK" != "True" ]] && fail "runTurn failed: $MSG"
ASSISTANT=$(echo "$MSG" | python3 -c "
import sys,json
d=json.load(sys.stdin)['data']
for m in d['messages']:
  if m['type']=='ASSISTANT_TEXT':
    print(m.get('content',''))
    break
")
[[ -z "$ASSISTANT" ]] && fail "no ASSISTANT_TEXT in response"
echo "  assistant: ${ASSISTANT:0:120}"
ok "runTurn 成功，含 ASSISTANT_TEXT"

step "⑧ GET /agent/memories 验证 user memory + ORG memory 可见"
LIST=$(curl -sk "$API_BASE/agent/memories" "${HDR[@]:0:4}")
dump "$LIST"
USER_VISIBLE=$(echo "$LIST" | python3 -c "
import sys,json
items=json.load(sys.stdin)['data']['items']
print(any(m['id']=='$MEM_ID' for m in items))
")
ORG_VISIBLE=$(echo "$LIST" | python3 -c "
import sys,json
items=json.load(sys.stdin)['data']['items']
print(any(m['id']=='$ORG_MEM_ID' for m in items))
")
[[ "$USER_VISIBLE" != "True" ]] && fail "user memory not in list"
[[ "$ORG_VISIBLE" != "True" ]] && fail "ORG memory not in user-visible list"
ok "GET /agent/memories 含 USER + ORG 两条"

step "⑨ Cleanup（删 session / memories / persona）"
curl -sk -X DELETE "$API_BASE/agent/memories/$MEM_ID" "${HDR[@]:0:4}" >/dev/null
curl -sk -X DELETE "$API_BASE/agent/admin/memories/$ORG_MEM_ID" "${HDR[@]:0:4}" >/dev/null
curl -sk -X DELETE "$API_BASE/agent/sessions/$SESS_ID" "${HDR[@]:0:4}" >/dev/null
curl -sk -X DELETE "$API_BASE/agent/personas/$PERSONA_ID" "${HDR[@]:0:4}" >/dev/null
ok "cleanup done"

echo ""
echo "════════════════════════════════════════════"
echo "🎉 FFAI Agent smoke test PASSED"
echo "  覆盖：登录 / org 解析 / persona 建 + 绑 session / USER 私有 memory /"
echo "       ORG 共享 memory（admin endpoint）/ runTurn 走完整 LLM pipeline / list 含两层"
echo "════════════════════════════════════════════"
