"""
cdp_set_author_original.py
功能：
  1. 填写页面顶部"作者"输入框为 "2026"
  2. 点击"未声明"打开原创声明弹窗
     - 关闭可能出现的干扰弹窗（"我知道了"）
  3. 在原创弹窗内填写"作者"（必填，否则无法点确定）
  4. 勾选"我已阅读并同意《微信公众平台原创声明及相关功能使用协议》"
  5. 点击"确定"完成原创声明
  6. 截图验证
"""
import sys, json, socket, urllib.request, urllib.parse, time
sys.stdout.reconfigure(encoding='utf-8')

AUTHOR = "升学有陆"
HOST, PORT = 'localhost', 9222

# ── 获取编辑页面 ──────────────────────────────────────────────
pages = json.loads(urllib.request.urlopen(f'http://{HOST}:{PORT}/json').read())
page = next((p for p in pages if 'appmsg' in p.get('url','') and 'action=edit' in p.get('url','')), None)
if not page:
    print("[ERROR] 未找到公众号编辑页面，请先打开编辑界面")
    sys.exit(1)

ws_url = page['webSocketDebuggerUrl']
print(f"[OK] 编辑页面: {page['id']}")

# ── 建立 WebSocket 连接 ───────────────────────────────────────
parsed = urllib.parse.urlparse(ws_url)
sock = socket.create_connection((parsed.hostname, parsed.port or 80), timeout=10)
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)

_mid = [0]
def call(expr):
    _mid[0] += 1
    mid = _mid[0]
    data = json.dumps({'id': mid, 'method': 'Runtime.evaluate',
                       'params': {'expression': expr, 'returnByValue': True}}).encode('utf-8')
    n = len(data)
    mask = b'\x01\x02\x03\x04'
    if n <= 125:
        hdr = b'\x81' + bytes([n | 0x80]) + mask
    elif n < 65536:
        hdr = b'\x81\xfe' + n.to_bytes(2, 'big') + mask
    else:
        hdr = b'\x81\xff' + n.to_bytes(8, 'big') + mask
    sock.send(hdr + bytes(data[i] ^ mask[i % 4] for i in range(n)))
    sock.settimeout(8)
    buf = b''
    while True:
        try:
            buf += sock.recv(65536)
            n2 = buf[1] & 0x7f; off = 2
            if n2 == 126: n2 = int.from_bytes(buf[2:4], 'big'); off = 4
            elif n2 == 127: n2 = int.from_bytes(buf[2:10], 'big'); off = 10
            if len(buf) >= off + n2:
                obj = json.loads(buf[off:off + n2].decode('utf-8'))
                if obj.get('id') == mid:
                    return obj['result']['result'].get('value', '')
                buf = buf[off + n2:]
        except socket.timeout:
            return 'timeout'

# ── Step 1: 填写页面顶部作者框 ────────────────────────────────
print("\n[Step 1] 填写页面作者...")
r = call(f"""
(function(){{
    var input = document.querySelector('#author');
    if(!input) return 'author_not_found';
    var nativeSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set;
    nativeSetter.call(input, {json.dumps(AUTHOR)});
    input.dispatchEvent(new Event('input', {{bubbles:true}}));
    input.dispatchEvent(new Event('change', {{bubbles:true}}));
    return 'ok:' + input.value;
}})()
""")
print(f"[结果] {r}")
time.sleep(0.5)

# ── Step 2: 关闭可能存在的干扰弹窗 ───────────────────────────
print("\n[Step 2] 关闭干扰弹窗...")
r = call("""
(function(){
    var btns = Array.from(document.querySelectorAll('button'));
    var btn = btns.find(function(el){
        return (el.innerText||'').trim() === '我知道了'
            && window.getComputedStyle(el).display !== 'none';
    });
    if(btn){ btn.click(); return 'closed'; }
    return 'none';
})()
""")
print(f"[结果] {r}")
if r == 'closed':
    time.sleep(0.8)

# ── Step 3: 点击"未声明"打开原创弹窗 ─────────────────────────
print("\n[Step 3] 点击'未声明'...")
r = call("""
(function(){
    var btn = document.querySelector('.setting-group__switch.js_original_apply.js_edit_ori');
    if(!btn) return 'not_found';
    var txt = (btn.innerText||'').trim();
    if(txt !== '未声明') return 'already_set:' + txt;
    btn.click();
    return 'clicked';
})()
""")
print(f"[结果] {r}")

if r.startswith('already_set'):
    print("[INFO] 原创已声明，跳过")
    sock.close()
    sys.exit(0)

time.sleep(1.5)

# ── Step 3b: 关闭可能再次弹出的干扰弹窗（不关闭原创弹窗） ────
print("\n[Step 3b] 再次检查干扰弹窗...")
r = call("""
(function(){
    // 找"我知道了"按钮，但要确认不是在原创弹窗内
    var btns = Array.from(document.querySelectorAll('button'));
    var btn = btns.find(function(el){
        return (el.innerText||'').trim() === '我知道了'
            && window.getComputedStyle(el).display !== 'none';
    });
    if(btn){ btn.click(); return 'closed'; }
    return 'none';
})()
""")
print(f"[结果] {r}")
if r == 'closed':
    time.sleep(0.8)

# ── Step 4: 填写原创弹窗内的"作者"输入框 ─────────────────────
print("\n[Step 4] 填写原创弹窗内的作者...")
r = call(f"""
(function(){{
    var dialog = document.querySelector('.claim__original-dialog');
    if(!dialog) return 'dialog_not_found';
    // 找 placeholder="请输入作者" 的输入框（区分赞赏账户搜索框）
    var inputs = Array.from(dialog.querySelectorAll('input[type=text]'));
    var authorInput = inputs.find(function(el){{
        return el.placeholder === '请输入作者' || el.classList.contains('js_counter');
    }});
    if(!authorInput) return 'author_input_not_found';

    // 先聚焦
    // 先聚焦，选中全部内容后清空
    authorInput.focus();
    authorInput.select();
    document.execCommand('delete');

    // 用 execCommand insertText 模拟真实打字（最接近用户行为）
    var text = {json.dumps(AUTHOR)};
    document.execCommand('insertText', false, text);

    // 补发 change/blur 确保 Vue 响应
    authorInput.dispatchEvent(new Event('change', {{bubbles:true}}));
    authorInput.dispatchEvent(new Event('blur', {{bubbles:true}}));

    return 'ok:' + authorInput.value;
}})()
""")
print(f"[结果] {r}")
time.sleep(0.5)

# ── Step 5: 勾选"我已阅读并同意" ─────────────────────────────
print("\n[Step 5] 勾选同意协议...")
r = call("""
(function(){
    var dialog = document.querySelector('.claim__original-dialog');
    if(!dialog) return 'dialog_not_found';
    // 找最后一个 checkbox（同意协议的）
    var checkboxes = Array.from(dialog.querySelectorAll('input[type=checkbox]'));
    // 找包含"已阅读"文字的父级附近的 checkbox
    var agreeCb = null;
    checkboxes.forEach(function(cb){
        var container = cb.closest('label') || cb.parentElement || cb;
        var txt = (container.innerText || container.textContent || '');
        if(txt.includes('已阅读') || txt.includes('同意')){
            agreeCb = cb;
        }
    });
    // fallback: 找 .weui-desktop-form__checkbox 类型
    if(!agreeCb){
        agreeCb = dialog.querySelector('input.weui-desktop-form__checkbox');
    }
    if(!agreeCb) return 'checkbox_not_found';
    if(agreeCb.checked) return 'already_checked';
    agreeCb.click();
    return 'checked:' + agreeCb.checked;
})()
""")
print(f"[结果] {r}")
time.sleep(1.0)  # 等勾选后按钮变为可点击

# ── Step 6: 点击"确定" ────────────────────────────────────────
print("\n[Step 6] 点击'确定'...")
r = call("""
(function(){
    // 优先在原创弹窗内找"确定"按钮
    var dialog = document.querySelector('.claim__original-dialog');
    if(dialog){
        // 往上找父级 weui-desktop-dialog，然后找 ft 区域的确定
        var wrap = dialog.closest('.weui-desktop-dialog__wrp') || dialog.closest('.weui-desktop-dialog') || dialog.parentElement;
        if(wrap){
            var btns = Array.from(wrap.querySelectorAll('button'));
            var btn = btns.find(function(b){
                return (b.innerText||'').trim() === '确定'
                    && window.getComputedStyle(b).display !== 'none';
            });
            if(btn){ btn.click(); return 'clicked_in_dialog_wrap'; }
        }
    }
    // fallback: 全局找可见的"确定"按钮（排除disabled）
    var allBtns = Array.from(document.querySelectorAll('button'));
    var btn = allBtns.find(function(b){
        return (b.innerText||'').trim() === '确定'
            && !b.disabled
            && window.getComputedStyle(b).display !== 'none'
            && window.getComputedStyle(b).visibility !== 'hidden';
    });
    if(btn){ btn.click(); return 'clicked_global'; }
    return 'confirm_not_found';
})()
""")
print(f"[结果] {r}")
time.sleep(1.0)

# ── Step 7: 验证原创状态 ──────────────────────────────────────
print("\n[Step 7] 验证原创声明状态...")
r = call("""
(function(){
    var btn = document.querySelector('.setting-group__switch.js_original_apply.js_edit_ori');
    if(!btn) return 'element_not_found';
    return 'status:' + (btn.innerText||'').trim();
})()
""")
print(f"[结果] {r}")

# ── Step 8: 截图 ──────────────────────────────────────────────
print("\n[Step 8] 截图确认...")
_mid[0] += 1
mid = _mid[0]
data = json.dumps({'id': mid, 'method': 'Page.captureScreenshot', 'params': {'format': 'png'}}).encode('utf-8')
n = len(data)
mask = b'\x01\x02\x03\x04'
hdr = b'\x81' + bytes([n|0x80]) + mask if n<=125 else b'\x81\xfe' + n.to_bytes(2,'big') + mask
sock.send(hdr + bytes(data[i]^mask[i%4] for i in range(n)))
sock.settimeout(10)
buf = b''
while True:
    try:
        buf += sock.recv(65536)
        n2 = buf[1]&0x7f; off=2
        if n2==126: n2=int.from_bytes(buf[2:4],'big'); off=4
        elif n2==127: n2=int.from_bytes(buf[2:10],'big'); off=10
        if len(buf)>=off+n2:
            obj=json.loads(buf[off:off+n2].decode('utf-8'))
            if obj.get('id')==mid and 'result' in obj:
                import base64
                imgdata = obj['result'].get('result',{}).get('data') or obj['result'].get('data','')
                if imgdata:
                    with open('author_original_set.png','wb') as f:
                        f.write(base64.b64decode(imgdata))
                    print("[OK] 截图已保存: author_original_set.png")
                break
            buf=buf[off+n2:]
    except socket.timeout:
        print("[WARN] 截图超时")
        break

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