"""Standalone Playwright screenshot worker (fresh process, Windows-safe).

Invoked by fidelity_loop.capture_real_app_screenshot — never import uvicorn here.
"""
from __future__ import annotations

import asyncio
import base64
import json
import os
import sys
from pathlib import Path


def _force_proactor() -> None:
    if sys.platform == "win32":
        asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())


async def _shot_async(payload: dict) -> tuple[bytes | None, str, str | None]:
    from playwright.async_api import async_playwright

    draft = payload.get("draft") or {}
    rows = payload.get("rows") or []
    web = (os.getenv("WEB_BASE") or "http://127.0.0.1:5173").rstrip("/")
    goto_timeout = int(os.getenv("FIDELITY_GOTO_TIMEOUT_MS") or "45000")
    slug = str(((draft.get("meta") or {}).get("slug")) or "preview")
    preview_id = str(payload.get("preview_id") or "preview")
    inject_payload = {
        "ok": True,
        "id": preview_id,
        "blueprint": draft,
        "rows": rows,
        "resource": payload.get("resource") or "records",
    }
    inject_js = (
        "try{localStorage.removeItem('ajz_session');}catch(e){}"
        "window.__AJZ_PREVIEW__ = "
        + json.dumps(inject_payload, ensure_ascii=False)
        + ";"
    )
    target = f"{web}/#/preview/{preview_id}"

    def fmt(err: BaseException) -> str:
        msg = str(err).strip() or repr(err)
        return msg.replace("\n", " ")[:500]

    try:
        async with async_playwright() as p:
            browser = await p.chromium.launch(headless=True)
            try:
                page = await browser.new_page(viewport={"width": 1600, "height": 1100})
                await page.add_init_script(inject_js)

                async def fulfill(route):
                    await route.fulfill(
                        status=200,
                        content_type="application/json; charset=utf-8",
                        body=json.dumps(inject_payload, ensure_ascii=False).encode("utf-8"),
                    )

                await page.route("**/api/v1/preview/**", fulfill)
                await page.route("**/ai/api/v1/preview/**", fulfill)
                await page.goto(target, wait_until="domcontentloaded", timeout=goto_timeout)
                await page.evaluate(inject_js)
                try:
                    await page.wait_for_selector(
                        ".sf-shell-bar, .sf-root, .gen-app-ops, .gen-app, .sf-line-wrap",
                        timeout=45000,
                    )
                except Exception:
                    try:
                        snip = (await page.locator("body").inner_text(timeout=2000))[:240]
                    except Exception:
                        snip = page.url
                    raise RuntimeError(
                        f"preview shell missing. page={page.url} text={snip!r}"
                    ) from None
                login_btns = page.locator("button").filter(has_text="登录")
                shell = page.locator(".sf-shell-bar, .sf-root, .gen-app")
                if await login_btns.count() and not await shell.count():
                    raise RuntimeError("preview fell back to login")
                await page.wait_for_timeout(2500)
                if await page.locator(".gen-app").count():
                    png = await page.locator(".gen-app").first.screenshot(type="png")
                else:
                    png = await page.screenshot(type="png", full_page=True)
            finally:
                await browser.close()
        return (
            png,
            f"已截取草稿预览（/#/preview/{preview_id}，注入数据无需再拉 AI）参与对比",
            slug,
        )
    except Exception as e:  # noqa: BLE001
        return None, f"真页面截图失败: preview={fmt(e)}（目标 {target}）", slug


def main() -> int:
    _force_proactor()
    inp = Path(os.environ["FIDELITY_SHOT_INPUT"])
    outp = Path(os.environ["FIDELITY_SHOT_OUTPUT"])
    payload = json.loads(inp.read_text(encoding="utf-8"))
    png, note, slug = asyncio.run(_shot_async(payload))
    out_dir = os.getenv("FIDELITY_SHOT_DIR") or ""
    if png and out_dir:
        d = Path(out_dir)
        d.mkdir(parents=True, exist_ok=True)
        (d / f"preview_{payload.get('preview_id') or 'x'}.png").write_bytes(png)
    outp.write_text(
        json.dumps(
            {
                "png_b64": base64.b64encode(png).decode("ascii") if png else None,
                "note": note,
                "slug": slug,
            },
            ensure_ascii=False,
        ),
        encoding="utf-8",
    )
    return 0 if png else 2


if __name__ == "__main__":
    raise SystemExit(main())
