# -*- coding: utf-8 -*-
"""详细列出所有 input 元素"""
import sys, socket, json
sys.stdout.reconfigure(encoding="utf-8")

HOST = "localhost"
PORT = 28800
PAGE_ID = "70039F329097C14448996F189E3A42A1"

def make_ws():
    import urllib.parse
    u = "ws://%s:%s/devtools/page/%s" % (HOST, PORT, PAGE_ID)
    p = urllib.parse.urlparse(u)
    s = socket.create_connection((p.hostname, p.port or 80), timeout=15)
    req = (
        "GET %s HTTP/1.1\r\nHost: %s:%s\r\nUpgrade: websocket\r\n"
        "Connection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
        "Sec-WebSocket-Version: 13\r\n\r\n"
    ) % (p.path, p.hostname, p.port)
    s.send(req.encode())
    resp = b""
    while b"\r\n\r\n" not in resp:
        resp += s.recv(4096)
    return s

def ws_send(sock, data):
    data = data.encode("utf-8")
    n = len(data)
    m = b"\x01\x02\x03\x04"
    if n <= 125:
        h = bytes([0x81, n | 0x80]) + m
    elif n <= 65535:
        h = bytes([0x81, 0xFE]) + n.to_bytes(2, "big") + m
    else:
        h = bytes([0x81, 0xFF]) + n.to_bytes(8, "big") + m
    sock.send(h + bytes(data[i] ^ m[i % 4] for i in range(n)))

def ws_recv(sock):
    h = b""
    while len(h) < 2:
        h += sock.recv(2 - len(h))
    n = h[1] & 0x7F
    if n == 126:
        nb = b""
        while len(nb) < 2:
            nb += sock.recv(2 - len(nb))
        n = int.from_bytes(nb, "big")
    elif n == 127:
        nb = b""
        while len(nb) < 8:
            nb += sock.recv(8 - len(nb))
        n = int.from_bytes(nb, "big")
    body = b""
    while len(body) < n:
        body += sock.recv(n - len(body))
    return body.decode("utf-8")

_mid = [0]

def cdp(sock, method, params=None):
    if params is None:
        params = {}
    _mid[0] += 1
    ws_send(sock, json.dumps({"id": _mid[0], "method": method, "params": params}))
    sock.settimeout(20)
    for _ in range(300):
        try:
            r = json.loads(ws_recv(sock))
            if r.get("id") == _mid[0]:
                return r
        except Exception:
            pass
    return None

sock = make_ws()
print("[OK] Connected\n")

# 列出所有 input 的完整属性
r = cdp(sock, "Runtime.evaluate", {
    "expression": """
    (function() {
        var inputs = document.querySelectorAll('input');
        var results = [];
        for (var i = 0; i < inputs.length; i++) {
            var inp = inputs[i];
            var rect = inp.getBoundingClientRect();
            var style = window.getComputedStyle(inp);
            results.push({
                index: i,
                type: inp.type,
                accept: inp.accept || '',
                id: inp.id || '',
                name: inp.name || '',
                className: (inp.className || '').substring(0, 40),
                visible: rect.width > 0 && rect.height > 0,
                display: style.display,
                opacity: style.opacity,
                w: Math.round(rect.width),
                h: Math.round(rect.height),
                multiple: inp.multiple,
                // 父元素信息
                parentTag: inp.parentElement ? inp.parentElement.tagName : '',
                parentClass: inp.parentElement ? (inp.parentElement.className || '').substring(0, 40) : '',
                grandparentTag: inp.parentElement && inp.parentElement.parentElement ? inp.parentElement.parentElement.tagName : '',
                // 是否在封面区域
                nearCover: false
            });
        }
        // 检查哪些 input 在"封面"文字附近
        var coverLabel = null;
        var all = document.querySelectorAll('*');
        for (var el of all) {
            if ((el.textContent || '').indexOf('封面') === 0 && el.children.length === 0 && el.tagName !== 'BODY') {
                coverLabel = el;
                break;
            }
        }
        if (coverLabel) {
            for (var i = 0; i < results.length; i++) {
                var inp = inputs[i];
                var dist = 0;
                var p = inp;
                while (p && p !== coverLabel.parentElement) {
                    p = p.parentElement;
                    dist++;
                }
                if (p) results[i].nearCover = true;
            }
        }
        return JSON.stringify(results, null, 2);
    })()
    """,
    "returnByValue": True
})
val = r.get("result", {}).get("result", {}).get("value", "") if r else ""
print(val)

# 用 CDP 获取 backendNodeId 来调用 setFileInputFiles
print("\n[2] DOM.querySelectorAll for all inputs...")
r = cdp(sock, "DOM.getDocument", {"depth": 0})
root = r["result"]["root"]["nodeId"]
print("  root:", root)

r = cdp(sock, "DOM.querySelectorAll", {"nodeId": root, "selector": "input[type=file]"})
nodeIds = r["result"]["nodeIds"]
print("  file input nodeIds:", nodeIds)

# 获取每个的 backendNodeId
for nid in nodeIds:
    r = cdp(sock, "DOM.resolveNode", {"nodeId": nid})
    obj = r.get("result", {}).get("object", {})
    print("  nodeId=%s -> backendNodeId=%s className=%s" % (nid, obj.get("className", "?"), obj.get("description", "")))

sock.close()
print("\nDone")
