from __future__ import annotations

import json
import sys
from pathlib import Path

from dotenv import load_dotenv
from playwright.sync_api import sync_playwright

ROOT_DIR = Path(__file__).resolve().parents[1]
if str(ROOT_DIR) not in sys.path:
    sys.path.insert(0, str(ROOT_DIR))

from e2e.pages.wanyouji_member_page import WanyoujiMemberPage
from e2e.utils.account_store import account_store


OUT_DIR = Path("runtime/member_probe/manual_invite_operation")
WAIT_SECONDS = 90


def main() -> None:
    load_dotenv()
    store = account_store()
    parent = store.find_wanyouji_owner_for_member()
    if parent is None:
        raise SystemExit("台账中没有已开通丸友集产品的主账号")

    OUT_DIR.mkdir(parents=True, exist_ok=True)
    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(headless=False, slow_mo=80)
        context = browser.new_context(viewport={"width": 1920, "height": 1080})
        page = context.new_page()
        member_page = WanyoujiMemberPage(page, "https://test-lianlianyun.lianlianwz.com/home")
        member_page.login_main_account(parent.phone, parent.password)
        frame = member_page.open_member_management()
        member_page.open_add_member_modal(frame)
        install_recorder(frame)
        dump(page, frame, "01_等待手动操作前")
        print(
            f"已打开企业管理-成员管理-邀请员工弹窗。请在 {WAIT_SECONDS} 秒内手动完成："
            "点击产品下拉、选择丸友集、选择部门、选择打手角色。"
        )
        page.wait_for_timeout(WAIT_SECONDS * 1000)
        dump(page, frame, "02_手动操作后")
        context.close()
        browser.close()


def install_recorder(frame) -> None:
    frame.evaluate(
        """() => {
            window.__manualInviteEvents = [];
            const describe = el => {
              if (!el) return null;
              const r = el.getBoundingClientRect();
              const path = [];
              let cur = el;
              for (let i = 0; cur && i < 8; i += 1, cur = cur.parentElement) {
                path.push({
                  tag: cur.tagName,
                  id: cur.id || '',
                  className: String(cur.className || ''),
                  role: cur.getAttribute?.('role') || '',
                  ariaExpanded: cur.getAttribute?.('aria-expanded') || '',
                  ariaControls: cur.getAttribute?.('aria-controls') || '',
                  text: (cur.innerText || cur.textContent || '').trim().slice(0, 200),
                  rect: (() => {
                    const cr = cur.getBoundingClientRect();
                    return { x: cr.x, y: cr.y, width: cr.width, height: cr.height };
                  })(),
                });
              }
              return {
                tag: el.tagName,
                id: el.id || '',
                className: String(el.className || ''),
                role: el.getAttribute?.('role') || '',
                ariaExpanded: el.getAttribute?.('aria-expanded') || '',
                ariaControls: el.getAttribute?.('aria-controls') || '',
                text: (el.innerText || el.textContent || '').trim().slice(0, 300),
                rect: { x: r.x, y: r.y, width: r.width, height: r.height },
                path,
              };
            };
            ['mousedown', 'mouseup', 'click', 'focusin', 'change', 'input'].forEach(type => {
              document.addEventListener(type, event => {
                window.__manualInviteEvents.push({
                  type,
                  time: new Date().toISOString(),
                  target: describe(event.target),
                  active: describe(document.activeElement),
                  dropdowns: Array.from(document.querySelectorAll('.ant-select-dropdown:not(.ant-select-dropdown-hidden) .ant-select-item-option'))
                    .map(el => {
                      const r = el.getBoundingClientRect();
                      return {
                        text: (el.innerText || el.textContent || '').trim(),
                        className: String(el.className || ''),
                        rect: { x: r.x, y: r.y, width: r.width, height: r.height },
                      };
                    })
                    .filter(item => item.rect.width > 0 && item.rect.height > 0),
                });
              }, true);
            });
        }"""
    )


def dump(page, frame, name: str) -> None:
    payload = {
        "page_url": page.url,
        "frame_url": frame.url,
        "frame_text": safe_frame_text(frame)[:5000],
        "events": safe_events(frame),
        "nodes": safe_nodes(frame),
    }
    (OUT_DIR / f"{name}.json").write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
    page.screenshot(path=OUT_DIR / f"{name}.png", full_page=True)


def safe_frame_text(frame) -> str:
    try:
        return frame.locator("body").inner_text(timeout=5000)
    except Exception as exc:
        return f"<无法读取 frame 文本：{exc}>"


def safe_events(frame) -> list[dict]:
    try:
        return list(frame.evaluate("() => window.__manualInviteEvents || []"))
    except Exception:
        return []


def safe_nodes(frame) -> list[dict]:
    return list(
        frame.evaluate(
            """() => Array.from(document.querySelectorAll('.ant-modal *, .ant-select-dropdown *'))
              .map((el, index) => {
                const r = el.getBoundingClientRect();
                return {
                  index,
                  tag: el.tagName,
                  text: (el.innerText || el.textContent || '').trim(),
                  id: el.id || '',
                  role: el.getAttribute?.('role') || '',
                  ariaExpanded: el.getAttribute?.('aria-expanded') || '',
                  ariaControls: el.getAttribute?.('aria-controls') || '',
                  className: String(el.className || ''),
                  rect: { x: r.x, y: r.y, width: r.width, height: r.height },
                };
              })
              .filter(item => item.rect.width > 0 && item.rect.height > 0)
              .filter(item => item.text || item.id || item.role || item.className.includes('select'))"""
        )
    )


if __name__ == "__main__":
    main()
