#!/usr/bin/env python3
"""第16轮诊断：IoT&A 自动化规则引擎 + 控件CDP 测试脚本"""
import json, urllib.request, urllib.error, sys, time, subprocess

GATEWAY = "http://localhost:8080"
CDP = "http://127.0.0.1:9225"

def req(method, path, body=None, headers=None):
    url = f"{GATEWAY}{path}"
    if headers is None:
        headers = {}
    if body is not None:
        data = json.dumps(body).encode()
        headers["Content-Type"] = "application/json"
    else:
        data = None
    try:
        r = urllib.request.Request(url, data=data, headers=headers, method=method)
        resp = urllib.request.urlopen(r, timeout=10)
        return json.loads(resp.read())
    except urllib.error.HTTPError as e:
        body = e.read().decode()
        try:
            return json.loads(body)
        except:
            return {"error": body, "status": e.code}
    except Exception as e:
        return {"error": str(e)}

def get_token():
    result = req("POST", "/api/v1/auth/login", {"username": "yeij0942", "password": "Jiang1143218570"})
    return result.get("token", "")

print("=" * 60)
print("1. JWT Token 获取")
print("=" * 60)
token = get_token()
if token:
    print(f"✅ Token 获取成功: {token[:40]}...")
else:
    print("❌ Token 获取失败")
    sys.exit(1)

auth_headers = {"Authorization": f"Bearer {token}"}

print("\n" + "=" * 60)
print("2. Automation 规则引擎 API CRUD 测试")
print("=" * 60)

# 2a. GET Rules (should be empty)
print("\n2a. GET /api/v1/automation/rules")
result = req("GET", "/api/v1/automation/rules", headers=auth_headers)
count = result.get("count", -1)
print(f"    count={count} {'✅' if count is not None else '⚠️'}")

# 2b. POST Create Rule
print("\n2b. POST /api/v1/automation/rules (创建规则)")
create_body = {
    "name": "测试规则-关灯",
    "description": "每天晚上22点关闭客厅灯",
    "trigger_type": "schedule",
    "trigger_config": {"time": "22:00", "days": ["mon","tue","wed","thu","fri"]},
    "actions": [{"type": "set_device", "device_id": "light-livingroom", "property": "status", "value": "off"}]
}
result = req("POST", "/api/v1/automation/rules", body=create_body, headers=auth_headers)
rule_id = result.get("rule", {}).get("id", "")
print(f"    success={result.get('success')} rule_id={rule_id[:16] if rule_id else 'N/A'}...")
if not result.get("success"):
    print(f"    ERROR: {json.dumps(result, indent=2, ensure_ascii=False)[:500]}")

# 2c. GET Rules after create
if rule_id:
    print("\n2c. GET /api/v1/automation/rules")
    result = req("GET", "/api/v1/automation/rules", headers=auth_headers)
    name0 = result.get("rules", [{}])[0].get("name", "N/A") if result.get("rules") else "N/A"
    print(f"    count={result.get('count')} first_name={name0}")

    # 2d. GET single
    print(f"\n2d. GET /api/v1/automation/rules/{rule_id}")
    result = req("GET", f"/api/v1/automation/rules/{rule_id}", headers=auth_headers)
    r = result.get("rule", {})
    print(f"    name={r.get('name')} trigger_type={r.get('trigger_type')} enabled={r.get('enabled')}")

    # 2e. PUT Update
    print(f"\n2e. PUT /api/v1/automation/rules/{rule_id}")
    result = req("PUT", f"/api/v1/automation/rules/{rule_id}", body={"name": "测试规则-已更新", "enabled": False}, headers=auth_headers)
    r = result.get("rule", {})
    print(f"    success={result.get('success')} name={r.get('name')} enabled={r.get('enabled')}")

    # 2f. DELETE
    print(f"\n2f. DELETE /api/v1/automation/rules/{rule_id}")
    result = req("DELETE", f"/api/v1/automation/rules/{rule_id}", headers=auth_headers)
    print(f"    success={result.get('success')}")

    # 2g. Verify deleted
    print("\n2g. GET /api/v1/automation/rules (验证删除)")
    result = req("GET", "/api/v1/automation/rules", headers=auth_headers)
    print(f"    count={result.get('count')} {'✅' if result.get('count') == 0 else '⚠️'}")

# 2h. Unauthenticated
print("\n2h. GET /api/v1/automation/rules (未认证)")
result = req("GET", "/api/v1/automation/rules")
print(f"    error={result.get('error','N/A')[:60]}")

# 2i. Manual trigger
print("\n2i. POST /api/v1/automation/rules/:id/trigger (手动触发)")
cbody = {"name": "触发测试", "trigger_type": "manual", "actions": [{"type": "notify", "title": "测试", "body": "通知"}]}
result = req("POST", "/api/v1/automation/rules", body=cbody, headers=auth_headers)
trid = result.get("rule", {}).get("id", "")
if trid:
    result = req("POST", f"/api/v1/automation/rules/{trid}/trigger", headers=auth_headers)
    print(f"    success={result.get('success')} msg={result.get('message','')}")
    req("DELETE", f"/api/v1/automation/rules/{trid}", headers=auth_headers)
else:
    print("    ❌ 创建失败")

# 2j. Scenes
print("\n2j. GET /api/v1/automation/scenes")
result = req("GET", "/api/v1/automation/scenes", headers=auth_headers)
print(f"    count={result.get('count')}")

print("\n" + "=" * 60)
print("3. IoT 调试服务测试")
print("=" * 60)

res = json.loads(urllib.request.urlopen("http://localhost:8083/api/v1/devices").read())
print(f"3a. 设备总数: {res.get('total', 0)}")
for d in res.get("devices", []):
    print(f"    {d['name']} ({d['type']}): {d.get('status','')}")

print("\n3b. Toggle light-bedroom")
r = urllib.request.Request("http://localhost:8083/api/v1/devices/light-bedroom/toggle", method="POST")
result = json.loads(urllib.request.urlopen(r).read())
dev = result.get("device", {})
print(f"    action={result.get('action')} {dev.get('name')} status={dev.get('status')}")

print("\n3c. Set temperature (ac-livingroom)")
r = urllib.request.Request("http://localhost:8083/api/v1/devices/ac-livingroom/set", 
    data=json.dumps({"field": "temperature", "value": 24}).encode(),
    headers={"Content-Type": "application/json"}, method="POST")
result = json.loads(urllib.request.urlopen(r).read())
dev = result.get("device", {})
print(f"    {dev.get('name')} temperature={dev.get('temperature')}°C")

print("\n3d. History")
result = json.loads(urllib.request.urlopen("http://localhost:8083/api/v1/devices/light-bedroom/history").read())
print(f"    device_id={result.get('device_id')} history={len(result.get('history',[]))} entries")

print("\n" + "=" * 60)
print("4. CDP 前端 IoT 控件验证")
print("=" * 60)

pages = json.loads(urllib.request.urlopen(f"{CDP}/json").read())
target = None
for p in pages:
    if "localhost:5199" in p.get("url", ""):
        target = p
        break

if target:
    ws_url = target.get("webSocketDebuggerUrl", "")
    print(f"4a. 目标页面: {target.get('title','')[:60]}")
    print(f"4b. WebSocket: {ws_url[:80]}...")
    
    # Use websockets to execute JS
    print("\n4c. CDP Runtime.evaluate 检查 IoTStatusBar")
    try:
        import asyncio
        try:
            import websockets
        except ImportError:
            print("    ⚠️ websockets not installed, trying pip install...")
            subprocess.run([sys.executable, "-m", "pip", "install", "websockets", "-q"], timeout=30)
            import websockets
        
        async def cdp_eval():
            async with websockets.connect(ws_url, max_size=2**24) as ws:
                # Runtime.enable
                await ws.send(json.dumps({"id": 1, "method": "Runtime.enable"}))
                await asyncio.wait_for(ws.recv(), timeout=5)
                
                # Evaluate JS
                js_code = """
                (function() {
                    var r = {};
                    var allDivs = document.querySelectorAll('div');
                    r.totalDivs = allDivs.length;
                    r.iotTexts = [];
                    for (var i = 0; i < allDivs.length; i++) {
                        var t = allDivs[i].textContent || '';
                        if (t.indexOf('IoT') !== -1 || t.indexOf('iot') !== -1) {
                            r.iotTexts.push(t.substring(0, 100));
                            if (r.iotTexts.length >= 10) break;
                        }
                    }
                    r.hasRoot = !!document.getElementById('root');
                    r.title = document.title;
                    r.bodyText = (document.body ? document.body.innerText : '').substring(0, 300);
                    return JSON.stringify(r);
                })()
                """
                await ws.send(json.dumps({"id": 2, "method": "Runtime.evaluate", 
                    "params": {"expression": js_code, "returnByValue": True}}))
                resp = await asyncio.wait_for(ws.recv(), timeout=10)
                data = json.loads(resp)
                result_val = data.get("result", {}).get("result", {}).get("value", "N/A")
                return result_val
        
        result = asyncio.new_event_loop().run_until_complete(cdp_eval())
        parsed = json.loads(result) if result and result != "N/A" else {}
        print(f"    title={parsed.get('title','')}")
        print(f"    hasRoot={parsed.get('hasRoot')} totalDivs={parsed.get('totalDivs')}")
        print(f"    iotTexts={parsed.get('iotTexts',[])}")
        print(f"    bodyText(first 300): {parsed.get('bodyText','')}")
    except Exception as e:
        print(f"    ❌ CDP 错误: {e}")
else:
    print("4a. ❌ 未找到 localhost:5199 页面")
    for p in pages:
        print(f"    {p.get('url','?')[:100]}")

print("\n" + "=" * 60)
print("5. tool-engine IoT 工具执行测试")
print("=" * 60)

# 5a. iot_query
print("\n5a. tool-engine iot_query")
r = urllib.request.Request("http://localhost:8092/api/v1/tools/execute",
    data=json.dumps({"tool": "iot_query", "arguments": {}}).encode(),
    headers={"Content-Type": "application/json"}, method="POST")
try:
    result = json.loads(urllib.request.urlopen(r, timeout=10).read())
    print(f"    output: {result.get('output','')[:200]}")
    if result.get('error'):
        print(f"    error: {result['error'][:200]}")
except Exception as e:
    print(f"    ❌ {e}")

# 5b. iot_control toggle
print("\n5b. tool-engine iot_control (toggle ac-livingroom)")
r = urllib.request.Request("http://localhost:8092/api/v1/tools/execute",
    data=json.dumps({"tool": "iot_control", "arguments": {"device_id": "ac-livingroom", "action": "toggle"}}).encode(),
    headers={"Content-Type": "application/json"}, method="POST")
try:
    result = json.loads(urllib.request.urlopen(r, timeout=10).read())
    print(f"    output: {result.get('output','')[:200]}")
    if result.get('error'):
        print(f"    error: {result['error'][:200]}")
except Exception as e:
    print(f"    ❌ {e}")

# 5c. iot_control set_temperature
print("\n5c. tool-engine iot_control (set_temperature 28)")
r = urllib.request.Request("http://localhost:8092/api/v1/tools/execute",
    data=json.dumps({"tool": "iot_control", "arguments": {"device_id": "ac-livingroom", "action": "set_temperature", "value": 28}}).encode(),
    headers={"Content-Type": "application/json"}, method="POST")
try:
    result = json.loads(urllib.request.urlopen(r, timeout=10).read())
    print(f"    output: {result.get('output','')[:200]}")
    if result.get('error'):
        print(f"    error: {result['error'][:200]}")
except Exception as e:
    print(f"    ❌ {e}")

print("\n" + "=" * 60)
print("诊断测试完成")
print("=" * 60)
