# -*- coding: utf-8 -*-
"""
百家号文章填写 - V2.0 风格：通过占位符匹配定位标题
"""
import sys, socket, json, time, urllib.request, base64, os, glob, random
sys.stdout.reconfigure(encoding='utf-8')

HOST = 'localhost'
PORT = 9223

# ============================================
# 测试数据
# ============================================
TITLE = '山东两所医学院更名对比：第二医科大学 vs 医药大学'

PARAGRAPHS = [
    ('normal', '这是在测试百家号发布的正文内容。'),
    ('normal', '2023年，潍坊医学院更名为山东第二医科大学。'),
    ('heading', '第一部分：更名对比'),
    ('normal', '滨州医学院更名为山东医药大学。'),
    ('divider', ''),
    ('normal', '这是结尾段落。'),
]

# 图片
def get_latest_image():
    image_dir = r'D:\wxpic'
    exts = ['*.jpg', '*.jpeg', '*.png', '*.gif', '*.bmp', '*.webp']
    all_images = []
    for ext in exts:
        all_images.extend(glob.glob(os.path.join(image_dir, ext)))
    if not all_images:
        return None
    return max(all_images, key=os.path.getmtime)

IMAGE_PATH = get_latest_image()
print(f"[INFO] 图片: {IMAGE_PATH if IMAGE_PATH else 'None'}")

def rand_sleep(s, t):
    time.sleep(random.uniform(s, t))

def ws_connect(pid):
    p = urllib.parse.urlparse(f"ws://{HOST}:{PORT}/devtools/page/{pid}")
    s = socket.create_connection((p.hostname, p.port or 80), timeout=15)
    s.send(f"GET {p.path} HTTP/1.1\r\nHost:{p.hostname}:{p.port}\r\nUpgrade:websocket\r\nConnection:Upgrade\r\nSec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version:13\r\n\r\n".encode())
    b = b''
    while b'\r\n\r\n' not in b:
        b += s.recv(4096)
    return s

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

def recv_f(sock):
    def rx(n):
        b = b''
        while len(b) < n:
            b += sock.recv(n - len(b))
        return b
    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')

mid = 0
def call(sock, expr, timeout=15):
    global mid
    mid += 1
    send_f(sock, json.dumps({'id': mid, 'method': 'Runtime.evaluate', 'params': {'expression': expr, 'returnByValue': True}}))
    sock.settimeout(timeout)
    while True:
        o = json.loads(recv_f(sock))
        if o.get('id') == mid:
            return o.get('result', {}).get('result', {}).get('value', '')

pages = json.loads(urllib.request.urlopen(f'http://{HOST}:{PORT}/json').read())
page_id = [p['id'] for p in pages if 'baijiahao.baidu.com' in p['url']][0]
sock = ws_connect(page_id)
print("[OK] CDP connected")

# ============================================
# Step 1: 填标题 - 通过 innerText 匹配占位符
# ============================================
print("\n[Step 1] 填标题 (通过占位符匹配)...")
r = call(sock, f"""
(function(){{
    // 通过 innerText 匹配找到标题区域
    var all = document.querySelectorAll('*');
    for(var el of all){{
        var t = (el.innerText||'').trim();
        if(t === '请输入标题（2 - 64字）' || t === '38/64' || t.includes('请输入标题')){{
            el.innerText = {json.dumps(TITLE)};
            el.dispatchEvent(new Event('input', {{bubbles:true}}));
            el.dispatchEvent(new Event('change', {{bubbles:true}}));
            return 'TITLE_BY_PLACEHOLDER:' + el.tagName + ':' + el.innerText.substring(0,40);
        }}
    }}
    
    // 如果没找到占位符，尝试 p 标签
    for(var p of document.querySelectorAll('p')){{
        var t = (p.innerText||'').trim();
        if(t === '请输入标题（2 - 64字）' || t === '38/64'){{
            p.innerText = {json.dumps(TITLE)};
            p.dispatchEvent(new Event('input', {{bubbles:true}}));
            return 'TITLE_BY_P:' + p.innerText.substring(0,40);
        }}
    }}
    
    return 'PLACEHOLDER_NOT_FOUND';
}})()
""")
print(f"  [title_by_placeholder] {r}")
rand_sleep(1, 2)

# ============================================
# Step 2: 填正文
# ============================================
print("\n[Step 2] 填正文...")

body_html_parts = []

if IMAGE_PATH and os.path.exists(IMAGE_PATH):
    with open(IMAGE_PATH, 'rb') as f:
        img_data = f.read()
    img_b64 = base64.b64encode(img_data).decode('utf-8')
    ext = os.path.splitext(IMAGE_PATH)[1].lower()
    img_mime = 'image/jpeg' if ext in ['.jpg', '.jpeg'] else 'image/png'
    body_html_parts.append(f'<p><img src="data:{img_mime};base64,{img_b64}" /></p>')
    print(f"  图片已编码 ({len(img_b64)} chars)")

for style, text in PARAGRAPHS:
    if style == 'normal':
        body_html_parts.append(f'<p>　　{text}</p>')
    elif style == 'heading':
        body_html_parts.append(f'<p style="font-size:18px;font-weight:bold;margin:12px 0 6px;color:#333;">{text}</p>')
    elif style == 'divider':
        body_html_parts.append('<p style="text-align:center;color:#999;margin:10px 0;">————————————————————</p>')

full_html = ''.join(body_html_parts)
print(f"  正文 HTML: {len(full_html)} chars")

r = call(sock, f"""
(function(){{
    var iframe = document.getElementById('ueditor_0');
    if(!iframe) return 'no_iframe';
    
    try{{
        var doc = iframe.contentDocument || iframe.contentWindow.document;
        doc.body.innerHTML = {json.dumps(full_html)};
        doc.body.dispatchEvent(new Event('input', {{bubbles:true}}));
        return 'BODY_OK:len=' + (doc.body.innerText||'').trim().length;
    }} catch(e){{
        return 'ERROR:' + e.message;
    }}
}})()
""")
print(f"  [set_body] {r}")
rand_sleep(2, 3)

# 验证
r = call(sock, """
(function(){
    var all = document.querySelectorAll('*');
    var titleText = '';
    for(var el of all){
        var t = (el.innerText||'').trim();
        if(t.includes('第二医科大') || t.includes('医药大学')){
            titleText = t.substring(0,50);
            break;
        }
    }
    
    var iframe = document.getElementById('ueditor_0');
    var bodyText = '';
    if(iframe){
        try{
            var doc = iframe.contentDocument || iframe.contentWindow.document;
            bodyText = (doc.body.innerText||'').trim().substring(0,50);
        }catch(e){}
    }
    
    return 'title=' + titleText + '|body=' + bodyText;
})()
""")
print(f"  [verify] {r}")

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