#!/usr/bin/env python3
"""
Phase 6.4 全鏈路測試腳本
========================

功能:
1. 觸發假告警 (建立 Incident)
2. 呼叫 /proposal 端點 (產生決策)
3. 呼叫 /approvals/pending (模擬前端撈取待簽核清單)
4. 證明這條鏈路完全暢通

使用方式:
    cd apps/api
    python scripts/test_phase64_proposal.py

驗收標準:
- Incident 成功建立
- Proposal 成功生成
- Proposal 出現在 /approvals/pending 清單中
- 前端零改動即可渲染
"""

import asyncio
import json
from datetime import datetime

import httpx

# API 端點
API_BASE = "http://localhost:8000"
SIGNALS_ENDPOINT = f"{API_BASE}/api/v1/webhooks/signals"
INCIDENTS_ENDPOINT = f"{API_BASE}/api/v1/incidents"
APPROVALS_ENDPOINT = f"{API_BASE}/api/v1/approvals/pending"


async def send_test_alert() -> dict | None:
    """發送測試告警"""
    alert = {
        "alert_name": "PodCrashLoopBackOff",
        "severity": "critical",  # P0
        "source": "prometheus",
        "namespace": "production",
        "target": "api-gateway",
        "fingerprint": f"fp_test_{datetime.now().strftime('%H%M%S')}",
        "labels": {
            "namespace": "production",
            "pod": "api-gateway-abc123",
        },
        "annotations": {
            "summary": "Pod api-gateway is in CrashLoopBackOff state",
        },
    }

    async with httpx.AsyncClient() as client:
        try:
            response = await client.post(
                SIGNALS_ENDPOINT,
                json=alert,
                timeout=10.0,
            )
            if response.status_code == 200:
                return response.json()
            else:
                print(f"    [ERROR] status_code: {response.status_code}")
                print(f"    [ERROR] response: {response.text}")
                return None
        except Exception as e:
            print(f"    [ERROR] {e}")
            return None


async def wait_for_incident(namespace: str, timeout: int = 10) -> str | None:
    """等待 Incident 被建立並返回 incident_id"""
    async with httpx.AsyncClient() as client:
        for _ in range(timeout):
            try:
                response = await client.get(
                    INCIDENTS_ENDPOINT,
                    timeout=5.0,
                )
                if response.status_code == 200:
                    data = response.json()
                    for incident in data.get("incidents", []):
                        # 找到我們的測試 Incident
                        if "api-gateway" in incident.get("affected_services", []):
                            return incident.get("incident_id")
            except Exception:
                pass
            await asyncio.sleep(1)
    return None


async def generate_proposal(incident_id: str) -> dict | None:
    """生成 Decision Proposal"""
    async with httpx.AsyncClient() as client:
        try:
            response = await client.post(
                f"{INCIDENTS_ENDPOINT}/{incident_id}/proposal",
                timeout=10.0,
            )
            if response.status_code == 200:
                return response.json()
            else:
                print(f"    [ERROR] status_code: {response.status_code}")
                print(f"    [ERROR] response: {response.text}")
                return None
        except Exception as e:
            print(f"    [ERROR] {e}")
            return None


async def get_pending_approvals() -> dict | None:
    """取得待簽核清單"""
    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(
                APPROVALS_ENDPOINT,
                timeout=10.0,
            )
            if response.status_code == 200:
                return response.json()
            else:
                print(f"    [ERROR] status_code: {response.status_code}")
                return None
        except Exception as e:
            print(f"    [ERROR] {e}")
            return None


async def main():
    """主測試流程"""
    print("=" * 70)
    print("Phase 6.4 全鏈路測試: Incident → Proposal → Pending Approvals")
    print("=" * 70)
    print(f"時間: {datetime.now().isoformat()}")
    print()

    # 0. 健康檢查
    print("[0] 檢查 API 健康狀態...")
    async with httpx.AsyncClient() as client:
        try:
            health = await client.get(f"{API_BASE}/api/v1/health", timeout=5.0)
            print(f"    API status: {health.status_code}")
        except Exception as e:
            print(f"    API 連線失敗: {e}")
            print("    請確認 API 已啟動: docker compose up -d")
            return

    # 1. 發送測試告警
    print("\n" + "-" * 70)
    print("[1] 發送測試告警 (建立 Incident)")
    print("-" * 70)

    result = await send_test_alert()
    if not result:
        print("    [FAIL] 無法發送告警")
        return

    print(f"    message_id: {result.get('message_id', 'N/A')}")
    print(f"    success: {result.get('success', False)}")

    # 2. 等待 Incident 建立
    print("\n" + "-" * 70)
    print("[2] 等待 Consumer 處理並建立 Incident (最多 10 秒)")
    print("-" * 70)

    incident_id = await wait_for_incident("production")

    if not incident_id:
        print("    [FAIL] 無法找到測試 Incident")
        print("    請檢查 API 日誌: docker logs awoooi-api --tail 50")
        return

    print(f"    incident_id: {incident_id}")
    print("    [OK] Incident 已建立")

    # 3. 生成 Proposal
    print("\n" + "-" * 70)
    print("[3] 呼叫 /proposal 端點生成決策")
    print("-" * 70)

    proposal_result = await generate_proposal(incident_id)

    if not proposal_result or not proposal_result.get("success"):
        print("    [FAIL] 無法生成 Proposal")
        print(f"    message: {proposal_result.get('message') if proposal_result else 'N/A'}")
        return

    proposal = proposal_result.get("proposal", {})
    print(f"    proposal_id: {proposal.get('id', 'N/A')}")
    print(f"    action: {proposal.get('action', 'N/A')[:60]}...")
    print(f"    risk_level: {proposal.get('risk_level', 'N/A')}")
    print(f"    required_signatures: {proposal.get('required_signatures', 'N/A')}")
    print(f"    incident_status: {proposal_result.get('incident_status', 'N/A')}")
    print("    [OK] Proposal 已生成")

    # 4. 驗證 /approvals/pending
    print("\n" + "-" * 70)
    print("[4] 呼叫 /approvals/pending 驗證前端相容性")
    print("-" * 70)

    pending = await get_pending_approvals()

    if not pending:
        print("    [FAIL] 無法取得待簽核清單")
        return

    print(f"    count: {pending.get('count', 0)}")

    # 尋找我們的 Proposal
    found = False
    for approval in pending.get("approvals", []):
        if approval.get("id") == proposal.get("id"):
            found = True
            print("    [FOUND] Proposal 出現在待簽核清單中!")
            print()
            print("    === PendingApprovalsResponse JSON ===")
            print(json.dumps({
                "count": pending.get("count"),
                "target_approval": approval,
            }, indent=2, ensure_ascii=False, default=str))
            break

    if not found:
        print("    [WARN] Proposal 未出現在待簽核清單中")
        print("    (可能因為 risk_level=LOW 已自動批准)")

    # 5. 最終驗證
    print("\n" + "=" * 70)
    print("驗證結果")
    print("=" * 70)

    checks = [
        ("Incident 建立", incident_id is not None),
        ("Proposal 生成", proposal_result.get("success", False)),
        ("風險評估", proposal.get("risk_level") is not None),
        ("狀態推進 (MITIGATING)", proposal_result.get("incident_status") == "mitigating"),
        ("前端相容 (/approvals/pending)", pending is not None),
    ]

    all_passed = True
    for name, passed in checks:
        status = "✅ PASS" if passed else "❌ FAIL"
        print(f"[{status}] {name}")
        if not passed:
            all_passed = False

    print()
    print("=" * 70)
    if all_passed:
        print("🎉 Phase 6.4 全鏈路測試 PASSED!")
        print("   大腦已具備決策輸出能力!")
        print("   Decision Proposal API 已鑄造完成!")
    else:
        print("💥 Phase 6.4 全鏈路測試 FAILED!")
        print("   請檢查上述失敗項目")
    print("=" * 70)


if __name__ == "__main__":
    asyncio.run(main())
