#!/usr/bin/env python3
"""CDP v3: 深度诊断前端白屏问题 — 检查 DOM、网络、JS 模块加载"""
import json, time, base64, urllib.request, os

# Step 1: 打开新页面
print("=== Step 1: 导航到前端页面 ===")
req = urllib.request.Request("http://127.0.0.1:9225/json/new?url=http://localhost:5199/", method="PUT")
resp = urllib.request.urlopen(req, timeout=10)
page_data = json.loads(resp.read())
page_id = page_data.get("id","")
ws_url = page_data.get("webSocketDebuggerUrl","")
print(f"  Page ID: {page_id}")
print(f"  WS URL: {ws_url[:80]}")

from websocket import create_connection
ws = create_connection(ws_url, timeout=10)

def cdp(method, params=None, msg_id=1):
    ws.send(json.dumps({"id": msg_id, "method": method, "params": params or {}}))

def recv_all(timeout=3):
    ws.settimeout(timeout)
    msgs = []
    try:
        while True:
            msgs.append(ws.recv())
    except:
        pass
    return msgs

def find_result(msgs, msg_id):
    for m in msgs:
        try:
            d = json.loads(m)
            if d.get("id") == msg_id:
                return d.get("result",{})
        except:
            pass
    return None

# Step 2: 启用所有 domains
print("\n=== Step 2: 启用所有 domains ===")
cdp("Page.enable", {}, 1)
cdp("Network.enable", {}, 2)
cdp("Runtime.enable", {}, 3)
cdp("Log.enable", {}, 4)
cdp("DOM.enable", {}, 5)
recv_all(1)

# Step 3: 重新 navigate 以捕获网络事件
print("\n=== Step 3: 重新导航 ===")
cdp("Page.navigate", {"url": "http://localhost:5199/"}, 10)
time.sleep(3)

# 收集在此期间的所有消息
print("  收集网络/运行时事件...")
all_msgs = recv_all(5)

# 分析网络事件
print("\n=== Step 4: 网络请求分析 ===")
requests = {}
for m in all_msgs:
    try:
        d = json.loads(m)
    except:
        continue
    method = d.get("method","")
    params = d.get("params",{})
    
    if method == "Network.requestWillBeSent":
        req_info = params.get("request", {})
        url = req_info.get("url","")
        req_id = params.get("requestId","")
        rtype = params.get("type","")
        requests[req_id] = {"url": url, "type": rtype, "status": "pending"}
    
    elif method == "Network.responseReceived":
        req_id = params.get("requestId","")
        resp = params.get("response",{})
        status = resp.get("status",0)
        mime = resp.get("mimeType","")
        if req_id in requests:
            requests[req_id]["status"] = status
            requests[req_id]["mime"] = mime
    
    elif method == "Network.loadingFailed":
        req_id = params.get("requestId","")
        err = params.get("errorText","")
        if req_id in requests:
            requests[req_id]["status"] = "FAILED"
            requests[req_id]["error"] = err
    
    elif method == "Runtime.exceptionThrown":
        exc = params.get("exceptionDetails",{})
        print(f"  [EXCEPTION] {exc.get('text','')} at {exc.get('url','')}:{exc.get('lineNumber','')}")
    
    elif method == "Log.entryAdded":
        entry = params.get("entry",{})
        print(f"  [CONSOLE:{entry.get('level','log')}] {entry.get('text','')[:200]}")
    
    elif method == "Runtime.consoleAPICalled":
        args = params.get("args",[])
        msg_type = params.get("type","log")
        texts = []
        for a in args:
            t = a.get("value","") or a.get("description","")
            texts.append(str(t)[:150])
        print(f"  [CONSOLE:{msg_type}] {' '.join(texts)}")

print(f"\n  Total network requests: {len(requests)}")
for rid, info in requests.items():
    status_str = str(info.get("status","?"))
    type_str = info.get("type","?")
    url_short = info.get("url","")[-80:]
    error_str = f" ERROR={info.get('error','')}" if info.get("error") else ""
    print(f"  [{type_str}] {status_str} {url_short}{error_str}")

# Step 5: 运行时评估 - 深度检查
print("\n=== Step 5: 运行时深度评估 ===")
checks = [
    ("window.location.href", "window.location.href"),
    ("document.readyState", "document.readyState"),
    ("document.title", "document.title"),
    ("root element", "document.getElementById('root') ? 'EXISTS' : 'NULL'"),
    ("body innerHTML length", "document.body ? document.body.innerHTML.length : -1"),
    ("body children count", "document.body ? document.body.children.length : -1"),
    ("head children count", "document.head ? document.head.children.length : -1"),
    ("all scripts", "Array.from(document.querySelectorAll('script')).map(s => ({src:s.src,type:s.type,async:s.async,defer:s.defer})).slice(0,5)"),
    ("React DOM check", "typeof React !== 'undefined' ? 'React global found' : (document.querySelector('#root') ? 'root exists but no React global' : 'root missing')"),
    ("SW registration check", "'serviceWorker' in navigator ? 'SW API available' : 'NO SW API'"),
    ("localStorage token", "localStorage.getItem('token') || 'no token'"),
]

for idx, (label, expr) in enumerate(checks):
    msg_id = 100 + idx
    cdp("Runtime.evaluate", {"expression": expr, "returnByValue": True}, msg_id)
    recv_msgs = recv_all(2)
    r = find_result(recv_msgs, msg_id)
    
    if r:
        val = r.get("result",{}).get("value","?")
        # 处理 object 类型
        if isinstance(val, dict) and "objectId" in r.get("result",{}):
            val = r["result"].get("description","[object]")
        err = r.get("result",{}).get("description","") or ""
        print(f"  {label}: {val}")
        if r.get("result",{}).get("type") == "object":
            # Try to get properties
            obj_id = r["result"].get("objectId","")
            if obj_id:
                cdp("Runtime.getProperties", {"objectId": obj_id, "ownProperties": True}, 900 + idx)
                prop_msgs = recv_all(2)
                prop_r = find_result(prop_msgs, 900 + idx)
                if prop_r:
                    for prop in prop_r.get("result",[]):
                        v = prop.get("value",{})
                        print(f"    .{prop.get('name','?')} = {v.get('value', v.get('description','?'))}")
    else:
        print(f"  {label}: NO RESULT")

# Step 6: 截图
print("\n=== Step 6: 截图 ===")
cdp("Page.captureScreenshot", {"format": "png", "captureBeyondViewport": True}, 20)
recv_msgs = recv_all(5)
r = find_result(recv_msgs, 20)
if r and r.get("data"):
    img = base64.b64decode(r["data"])
    fp = "/tmp/cyrene_screenshot_round12_v3.png"
    with open(fp, "wb") as f:
        f.write(img)
    print(f"  Screenshot: {len(img)} bytes -> {fp}")
else:
    print(f"  Screenshot failed: {str(r)[:200]}")

# Step 7: 检查是否有 JS 异常
print("\n=== Step 7: 最终 JS 异常检查 ===")
ws.settimeout(1)
has_exception = False
for i in range(5):
    try:
        d = json.loads(ws.recv())
        if d.get("method") == "Runtime.exceptionThrown":
            exc = d["params"]["exceptionDetails"]
            print(f"  [EXCEPTION] text={exc.get('text','')}")
            print(f"    url={exc.get('url','')}")
            print(f"    line={exc.get('lineNumber','')} col={exc.get('columnNumber','')}")
            stack = exc.get("stackTrace",{})
            for frame in stack.get("callFrames",[]):
                print(f"    at {frame.get('functionName','')} {frame.get('url','')}:{frame.get('lineNumber','')}")
            has_exception = True
    except:
        break

if not has_exception:
    print("  No exceptions caught")

ws.close()
print("\n[DONE v3]")
