# -*- coding: utf-8 -*-
"""诊断 UEditor 位置和状态"""
import sys, socket, json, time, urllib.request, base64, os
sys.stdout.reconfigure(encoding='utf-8')

HOST = "localhost"
PORT = 9222

def ws_connect(page_id):
    import urllib.parse
    ws_url = f"ws://{HOST}:{PORT}/devtools/page/{page_id}"
    parsed = urllib.parse.urlparse(ws_url)
    sock = socket.create_connection((parsed.hostname, parsed.port or 80), timeout=15)
    key = 'dGhlIHNhbXBsZSBub25jZQ=='
    handshake = (
        f'GET {parsed.path} HTTP/1.1\r\n'
        f'Host: {parsed.hostname}:{parsed.port}\r\n'
        'Upgrade: websocket\r\nConnection: Upgrade\r\n'
        f'Sec-WebSocket-Key: {key}\r\nSec-WebSocket-Version: 13\r\n\r\n'
    )
    sock.send(handshake.encode())
    resp = b''
    while b'\r\n\r\n' not in resp:
        resp += sock.recv(4096)
    return sock

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

def recv_frame(sock):
    def rx(n):
        buf = b''
        while len(buf) < n:
            buf += sock.recv(n - len(buf))
        return buf
    h = rx(2)
    n = h[1] & 0x7f
    if n == 126:
        n = int.from_bytes(rx(2), 'big')
    elif n == 127:
        n = int.from_bytes(rx(8), 'big')
    return rx(n).decode('utf-8')

_msg_id = 0
def call(sock, expr, timeout=20):
    global _msg_id
    _msg_id += 1
    mid = _msg_id
    send_frame(sock, json.dumps({
        'id': mid,
        'method': 'Runtime.evaluate',
        'params': {'expression': expr, 'returnByValue': True}
    }))
    sock.settimeout(timeout)
    while True:
        raw = recv_frame(sock)
        obj = json.loads(raw)
        if obj.get('id') == mid:
            res = obj.get('result', {}).get('result', {})
            return res.get('value', res.get('description', ''))

# 获取 page_id
resp = urllib.request.urlopen(f'http://{HOST}:{PORT}/json').read()
pages = json.loads(resp)
page_id = pages[0].get('id', '')
print(f"[PAGE_ID] {page_id}")

sock = ws_connect(page_id)
print("[OK] WebSocket 已连接\n")

# 检查主文档中的 UEditor
print("[主文档] 检查 UEditor...")
r = call(sock, """
(function() {
    var result = {
        hasUE_V2: !!(window.UE_V2),
        hasUE_instants: !!(window.UE_V2 && window.UE_V2.instants),
        instantCount: 0,
        instantKeys: [],
        hasContent: false
    };
    if (window.UE_V2 && window.UE_V2.instants) {
        var ks = Object.keys(window.UE_V2.instants);
        result.instantCount = ks.length;
        result.instantKeys = ks;
        for (var k of ks) {
            var inst = window.UE_V2.instants[k];
            if (inst && inst.key && inst.key.indexOf('content') > -1) {
                result.hasContent = true;
            }
        }
    }
    return JSON.stringify(result);
})()
""")
print(f"  {r}\n")

# 检查所有 iframe
print("[IFrame] 检查编辑器...")
r = call(sock, """
(function() {
    var iframes = document.querySelectorAll('iframe');
    var result = [];
    for (var i = 0; i < iframes.length; i++) {
        var iframe = iframes[i];
        var info = {
            index: i,
            hasUE_V2: false,
            hasInst: false,
            hasContent: false,
            hasBody: false,
            bodyLen: 0
        };
        try {
            var w = iframe.contentWindow || iframe.contentDocument.defaultView;
            var doc = iframe.contentDocument || iframe.contentWindow.document;
            info.hasUE_V2 = !!(w.UE_V2);
            if (w.UE_V2 && w.UE_V2.instants) {
                var ks = Object.keys(w.UE_V2.instants);
                info.hasInst = ks.length > 0;
                for (var k of ks) {
                    var inst = w.UE_V2.instants[k];
                    if (inst && inst.key && inst.key.indexOf('content') > -1) {
                        info.hasContent = true;
                    }
                }
            }
            var body = doc.querySelector('body');
            info.hasBody = !!body;
            if (body) {
                info.bodyLen = body.innerHTML.length;
            }
        } catch(e) {
            info.error = e.message;
        }
        result.push(info);
    }
    return JSON.stringify(result);
})()
""")
print(f"  {r}\n")

# 检查当前页面内容
print("[内容] 检查正文是否已有内容...")
r = call(sock, """
(function() {
    var iframes = document.querySelectorAll('iframe');
    for (var iframe of iframes) {
        try {
            var w = iframe.contentWindow || iframe.contentDocument.defaultView;
            var doc = iframe.contentDocument || iframe.contentWindow.document;
            var body = doc.querySelector('body');
            if (body) {
                return 'iframe_body_len=' + body.innerHTML.length + ', img_count=' + body.querySelectorAll('img').length;
            }
        } catch(e) {}
    }
    return 'no_body';
})()
""")
print(f"  {r}\n")

sock.close()
print("\n[DONE]")
