"""
RNS1.4 CHAT 模块端到端测试脚本
用法: python scripts/ops/test_chat_e2e.py

前置条件:
  - 后端服务已启动 (uvicorn app.main:app)
  - .env 中配置了 TEST_USER_TOKEN 和 APP_DB_DSN
  - test_zqyy_app 数据库可访问

环境变量:
  BACKEND_URL  — 后端地址，默认 http://localhost:8000
  TEST_USER_TOKEN — 测试用户 JWT token
  APP_DB_DSN — 业务数据库连接串（指向 test_zqyy_app）
"""
# CHANGE 2026-03-20 | RNS1.4 T13.1: CHAT 端到端测试脚本

import json
import os
import sys
import time
from pathlib import Path

# 加载根 .env
from dotenv import load_dotenv
load_dotenv(Path(__file__).resolve().parents[2] / ".env")

BACKEND_URL = os.environ.get("BACKEND_URL", "http://localhost:8000").rstrip("/")
TOKEN = os.environ.get("TEST_USER_TOKEN", "")
DB_DSN = os.environ.get("APP_DB_DSN", "")

if not TOKEN:
    print("❌ 缺少 TEST_USER_TOKEN 环境变量")
    sys.exit(1)
if not DB_DSN:
    print("❌ 缺少 APP_DB_DSN 环境变量")
    sys.exit(1)

import httpx
import psycopg2

HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
results: list[dict] = []


def record(name: str, passed: bool, detail: str = ""):
    status = "✅ PASS" if passed else "❌ FAIL"
    print(f"  {status} — {name}" + (f" ({detail})" if detail else ""))
    results.append({"test": name, "passed": passed, "detail": detail})


def main():
    print(f"\n🔗 后端: {BACKEND_URL}")
    print(f"🗄️  数据库: {DB_DSN[:40]}...\n")

    chat_id = None

    # ── CHAT-1: 对话历史列表 ──
    print("── CHAT-1: GET /api/xcx/chat/history ──")
    try:
        r = httpx.get(f"{BACKEND_URL}/api/xcx/chat/history", headers=HEADERS, timeout=10)
        record("CHAT-1 状态码 200", r.status_code == 200, f"got {r.status_code}")
        if r.status_code == 200:
            data = r.json()
            record("CHAT-1 返回 items 数组", isinstance(data.get("items"), list))
    except Exception as e:
        record("CHAT-1 请求", False, str(e))

    # ── 创建/获取对话（通过 general 入口）──
    print("\n── CHAT-2b: GET /api/xcx/chat/messages?contextType=general ──")
    try:
        r = httpx.get(
            f"{BACKEND_URL}/api/xcx/chat/messages",
            params={"contextType": "general", "contextId": ""},
            headers=HEADERS, timeout=10,
        )
        record("CHAT-2b 状态码 200", r.status_code == 200, f"got {r.status_code}")
        if r.status_code == 200:
            data = r.json()
            chat_id = data.get("chatId")
            record("CHAT-2b 返回 chatId", chat_id is not None, f"chatId={chat_id}")
    except Exception as e:
        record("CHAT-2b 请求", False, str(e))

    if not chat_id:
        print("\n⚠️  无法获取 chatId，跳过后续测试")
        _print_summary()
        return

    # ── CHAT-2a: 通过 chatId 查询消息 ──
    print(f"\n── CHAT-2a: GET /api/xcx/chat/{chat_id}/messages ──")
    try:
        r = httpx.get(
            f"{BACKEND_URL}/api/xcx/chat/{chat_id}/messages",
            headers=HEADERS, timeout=10,
        )
        record("CHAT-2a 状态码 200", r.status_code == 200, f"got {r.status_code}")
    except Exception as e:
        record("CHAT-2a 请求", False, str(e))

    # ── CHAT-3: 发送消息（同步） ──
    print(f"\n── CHAT-3: POST /api/xcx/chat/{chat_id}/messages ──")
    test_content = "你好，这是一条端到端测试消息，请简短回复。"
    ai_reply_id = None
    try:
        r = httpx.post(
            f"{BACKEND_URL}/api/xcx/chat/{chat_id}/messages",
            json={"content": test_content},
            headers=HEADERS, timeout=30,
        )
        record("CHAT-3 状态码 200", r.status_code == 200, f"got {r.status_code}")
        if r.status_code == 200:
            data = r.json()
            user_msg = data.get("userMessage", {})
            ai_msg = data.get("aiReply", {})
            record("CHAT-3 用户消息已返回", bool(user_msg.get("id")))
            record("CHAT-3 AI 回复已返回", bool(ai_msg.get("id")))
            record("CHAT-3 AI 回复非空", bool(ai_msg.get("content")))
            ai_reply_id = ai_msg.get("id")
            if ai_msg.get("content"):
                print(f"    AI 回复: {ai_msg['content'][:80]}...")
    except Exception as e:
        record("CHAT-3 请求", False, str(e))

    # ── CHAT-4: SSE 流式 ──
    print(f"\n── CHAT-4: POST /api/xcx/chat/stream (SSE) ──")
    sse_content = "请用一句话介绍台球运动。"
    sse_tokens: list[str] = []
    sse_done = False
    sse_message_id = None
    try:
        with httpx.stream(
            "POST",
            f"{BACKEND_URL}/api/xcx/chat/stream",
            json={"chatId": int(chat_id), "content": sse_content},
            headers=HEADERS,
            timeout=60,
        ) as resp:
            record("CHAT-4 状态码 200", resp.status_code == 200, f"got {resp.status_code}")
            current_event = ""
            for line in resp.iter_lines():
                if line.startswith("event:"):
                    current_event = line[6:].strip()
                elif line.startswith("data:"):
                    raw = line[5:].strip()
                    try:
                        d = json.loads(raw)
                    except json.JSONDecodeError:
                        continue
                    if current_event == "message" and "token" in d:
                        sse_tokens.append(d["token"])
                    elif current_event == "done":
                        sse_done = True
                        sse_message_id = d.get("messageId")
                    elif current_event == "error":
                        record("CHAT-4 收到 error 事件", False, d.get("message", ""))

        full_reply = "".join(sse_tokens)
        record("CHAT-4 收到 token 事件", len(sse_tokens) > 0, f"{len(sse_tokens)} tokens")
        record("CHAT-4 收到 done 事件", sse_done)
        record("CHAT-4 回复语义通顺", len(full_reply) > 5, f"len={len(full_reply)}")
        if full_reply:
            print(f"    SSE 回复: {full_reply[:80]}...")
    except Exception as e:
        record("CHAT-4 请求", False, str(e))

    # ── 数据库验证 ──
    print("\n── 数据库持久化验证 ──")
    try:
        conn = psycopg2.connect(DB_DSN)
        cur = conn.cursor()

        # 验证 ai_messages 包含用户消息和 AI 回复
        cur.execute(
            "SELECT id, role, tokens_used FROM biz.ai_messages "
            "WHERE conversation_id = %s ORDER BY created_at DESC LIMIT 4",
            (int(chat_id),),
        )
        rows = cur.fetchall()
        roles = [r[1] for r in rows]
        record("DB: ai_messages 有 user 消息", "user" in roles)
        record("DB: ai_messages 有 assistant 回复", "assistant" in roles)

        # 验证 tokens_used
        assistant_rows = [r for r in rows if r[1] == "assistant"]
        if assistant_rows:
            tokens = assistant_rows[0][2]
            record("DB: tokens_used 已记录", tokens is not None and tokens > 0,
                   f"tokens_used={tokens}")
        else:
            record("DB: tokens_used 已记录", False, "无 assistant 行")

        # 验证 ai_conversations 元数据更新
        cur.execute(
            "SELECT last_message, last_message_at FROM biz.ai_conversations WHERE id = %s",
            (int(chat_id),),
        )
        conv = cur.fetchone()
        if conv:
            record("DB: last_message 已更新", bool(conv[0]))
            record("DB: last_message_at 已更新", conv[1] is not None)
        else:
            record("DB: ai_conversations 记录存在", False)

        cur.close()
        conn.close()
    except Exception as e:
        record("DB 验证", False, str(e))

    _print_summary()


def _print_summary():
    print("\n" + "=" * 50)
    passed = sum(1 for r in results if r["passed"])
    failed = sum(1 for r in results if not r["passed"])
    print(f"总计: {len(results)} 项 | ✅ {passed} 通过 | ❌ {failed} 失败")

    # 输出 JSON 报告
    report_path = Path(__file__).parent / "chat_e2e_report.json"
    report_path.write_text(json.dumps(results, ensure_ascii=False, indent=2), encoding="utf-8")
    print(f"📄 报告已保存: {report_path}")


if __name__ == "__main__":
    main()
