"""
对外接口统一清单 / 能力矩阵 · 离线回归冒烟
（仅作回归，不替代真机 E2E；默认对 http://127.0.0.1:8899 发只读 GET）

跑法：
  SDK_BASE=http://127.0.0.1:8899 python3 -m pytest sdk/tests/test_integration_manifest.py -q
或直接：
  python3 sdk/tests/test_integration_manifest.py
"""

import os
import json
import urllib.request

BASE = os.environ.get("SDK_BASE", "http://127.0.0.1:8899")
DEVICE = os.environ.get("SDK_DEVICE_ID", "xgfe65eimrrofyws")

CONSUMERS = {"cunkebao", "superadmin", "ai_employee", "common"}
STATUSES = {"ready", "degraded", "offline"}


def _get(path: str) -> dict:
    with urllib.request.urlopen(f"{BASE}{path}", timeout=15) as resp:
        return json.loads(resp.read().decode("utf-8"))


def test_manifest_structure():
    d = _get("/api/v3/integration/manifest")["data"]
    assert d["total_endpoints"] > 100, "端点数应 >100"
    assert d["module_count"] >= 20, "模块数应 >=20"
    # other 桶应清零（全部归类）
    others = [m for m in d["modules"] if m["module"] == "other"]
    assert sum(m["endpoint_count"] for m in others) == 0, "other 桶必须清零"
    for m in d["modules"]:
        assert m["consumers"], f"模块 {m['module']} 必须有消费方"


def test_modules_runtime_tagged():
    d = _get("/api/v3/integration/modules")["data"]
    for m in d["modules"]:
        assert m.get("runtime") in {"server", "device", "hook"}, m


def test_consumer_views():
    for c in CONSUMERS:
        d = _get(f"/api/v3/integration/consumers/{c}")["data"]
        assert d["consumer"] == c
        assert d["total_endpoints"] >= 0
        for m in d["modules"]:
            assert c in m["consumers"]


def test_capability_matrix():
    d = _get(f"/api/v3/integration/capability/{DEVICE}?consumer=cunkebao")["data"]
    assert d["device_id"] == DEVICE
    assert set(d["summary"].keys()) == STATUSES
    for m in d["modules"]:
        assert m["status"] in STATUSES
        assert m["runtime"] in {"server", "device", "hook"}
    # server 模块无论设备是否在线都应 ready
    server_mods = [m for m in d["modules"] if m["runtime"] == "server"]
    for m in server_mods:
        assert m["status"] == "ready", f"server 模块 {m['module']} 应 ready"


def test_health():
    d = _get("/api/v3/integration/health")["data"]
    assert "checks" in d
    for key in ("websocket", "connection_provider", "cunkebao", "ai_gateway"):
        assert key in d["checks"], f"health 缺少 {key}"


if __name__ == "__main__":
    fails = 0
    for name, fn in list(globals().items()):
        if name.startswith("test_") and callable(fn):
            try:
                fn()
                print(f"  PASS {name}")
            except Exception as e:  # noqa: BLE001
                fails += 1
                print(f"  FAIL {name}: {e}")
    print("OK" if fails == 0 else f"{fails} FAILED")
    raise SystemExit(1 if fails else 0)
