from playwright.sync_api import sync_playwright
import os, time, re, traceback

URL = "https://creator.xiaohongshu.com/publish/publish"
IMAGE_PATH = os.path.abspath("test.jpg")

TITLE = "测试发布：自动化图文"
BODY = "这是一条 Playwright 自动发布测试。\n#测试 #自动化 #咖啡"

def click_tab_js(page, tab_text: str) -> bool:
    script = """
(t) => {
  const titles = Array.from(document.querySelectorAll("span.title"));
  const hit = titles.find(x => (x.textContent || "").trim() === t);
  if (!hit) return {ok:false, reason:"no-span-title"};
  const tab = hit.closest(".creator-tab") || hit.parentElement;
  if (!tab) return {ok:false, reason:"no-closest-tab"};
  tab.click();
  return {ok:true, reason:"clicked"};
}
"""
    res = page.evaluate(script, tab_text)
    print("JS_CLICK_RES =", res)
    return bool(res.get("ok"))

def find_editor_frame(page):
    for f in page.frames:
        try:
            if f.locator("input.upload-input[type='file']").count() > 0:
                return f
        except:
            pass
    return None

def upload_image(frame):
    loc = frame.locator("input.upload-input[type='file']")
    for i in range(min(loc.count(), 10)):
        el = loc.nth(i)
        acc = (el.get_attribute("accept") or "").lower()
        if any(x in acc for x in [".jpg", ".jpeg", ".png", ".webp"]):
            el.set_input_files(IMAGE_PATH)
            return True
    return False

def get_image_count(page) -> int:
    # 从“图片编辑 0/18”里取 0
    try:
        txt = page.locator("text=图片编辑").first.locator("xpath=..").inner_text()
        m = re.search(r"图片编辑\s*(\d+)\s*/\s*\d+", txt)
        if m:
            return int(m.group(1))
    except:
        pass

    # 兜底：全页搜
    try:
        body = page.inner_text("body")
        m = re.search(r"图片编辑\s*(\d+)\s*/\s*\d+", body)
        if m:
            return int(m.group(1))
    except:
        pass

    return -1

def wait_image_uploaded(page, start_cnt, timeout_sec=180):
    end = time.time() + timeout_sec
    while time.time() < end:
        cnt = get_image_count(page)
        print("IMG_CNT =", cnt)
        if cnt >= 1 and cnt != start_cnt:
            return True
        if "上传失败" in page.inner_text("body"):
            return False
        time.sleep(2)
    return False

def fill_title(frame, page):
    candidates = [
        "input[placeholder*='标题']",
        "textarea[placeholder*='标题']",
        "input[placeholder*='填写标题']",
        "textarea[placeholder*='填写标题']",
    ]
    for sel in candidates:
        try:
            el = frame.locator(sel).first
            if el.count() == 0:
                continue
            el.click(timeout=2000)
            el.fill("", timeout=2000)
            el.type(TITLE, delay=15)
            val = el.input_value()
            if val and TITLE[:4] in val:
                print("TITLE_OK =", sel)
                return True
        except:
            pass
    return False

def fill_body(frame, page):
    try:
        box = frame.locator("[contenteditable='true']").first
        if box.count() > 0:
            box.click(timeout=3000)
            page.keyboard.press("Meta+A")
            page.keyboard.type(BODY, delay=8)
            print("BODY_OK = contenteditable")
            return True
    except:
        pass
    return False

def click_publish(page):
    # 你截图里底部红色按钮就是“发布”
    # 优先点“发布”按钮（避免点到“发布笔记”这种入口按钮）
    try:
        page.locator("button:has-text('发布')").last.click(timeout=5000)
        print("PUBLISH_CLICKED = button 发布")
        return True
    except:
        pass

    for t in ["发布", "发布笔记", "立即发布"]:
        try:
            page.locator(f"text={t}").first.click(timeout=3000)
            print("PUBLISH_CLICKED =", t)
            return True
        except:
            pass
    print("PUBLISH_NOT_FOUND")
    return False

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    context = browser.new_context(storage_state="xhs_state.json")
    page = context.new_page()

    try:
        page.goto(URL, wait_until="domcontentloaded")
        page.wait_for_timeout(4000)
        click_tab_js(page, "上传图文")
        page.wait_for_timeout(1500)

        # 上传前读取一次计数
        start_cnt = get_image_count(page)
        print("START_IMG_CNT =", start_cnt)

        frame = find_editor_frame(page)
        if not frame:
            raise RuntimeError("找不到编辑 iframe")

        sent = upload_image(frame)
        print("UPLOAD_SENT =", sent)

        # 关键：等到 0/18 变成 1/18
        ok = wait_image_uploaded(page, start_cnt, timeout_sec=240)
        print("UPLOAD_DONE =", ok)

        if not ok:
            print("图片没有上传完成，停止发布（否则必进草稿）。")
        else:
            fill_title(frame, page)
            fill_body(frame, page)
            time.sleep(1)
            click_publish(page)

    except Exception as e:
        print("ERROR:", e)
        traceback.print_exc()

    input("按回车关闭浏览器...")
    browser.close()
