from __future__ import annotations

import json
import os
import sys
from datetime import datetime
from pathlib import Path
from threading import Event
from typing import Any

from playwright.sync_api import Frame, sync_playwright

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))

from e2e.conftest import settings as settings_fixture
from e2e.pages.wanzhanggui_order_page import WanyoujiFulfillmentPage
from e2e.pages.wanzhanggui_push_page import WANZHANGGUI_CONSOLE_URL


RECORDER_JS = r"""
() => {
  if (window.__codexPaycenterRecorderInstalled) return;
  window.__codexPaycenterRecorderInstalled = true;

  const shortText = (value) => String(value || '').replace(/\s+/g, ' ').trim().slice(0, 220);
  const cssPath = (el) => {
    if (!el || !el.tagName) return '';
    const parts = [];
    for (let node = el; node && node.nodeType === 1 && parts.length < 8; node = node.parentElement) {
      let part = node.tagName.toLowerCase();
      if (node.id) {
        part += `#${node.id}`;
        parts.unshift(part);
        break;
      }
      const cls = String(node.className || '').split(/\s+/).filter(Boolean).slice(0, 2);
      if (cls.length) part += '.' + cls.join('.');
      const parent = node.parentElement;
      if (parent) {
        const same = Array.from(parent.children).filter(item => item.tagName === node.tagName);
        if (same.length > 1) part += `:nth-of-type(${same.indexOf(node) + 1})`;
      }
      parts.unshift(part);
    }
    return parts.join(' > ');
  };
  const labelText = (el) => {
    const texts = [];
    const aria = el.getAttribute?.('aria-label');
    const placeholder = el.getAttribute?.('placeholder');
    if (aria) texts.push(aria);
    if (placeholder) texts.push(placeholder);
    for (let node = el; node && node !== document.body && texts.join(' ').length < 260; node = node.parentElement) {
      const text = shortText(node.innerText || node.textContent || '');
      if (text && text.length < 180) texts.push(text);
    }
    return shortText(Array.from(new Set(texts)).join(' | '));
  };
  const describe = (el) => {
    const r = el.getBoundingClientRect();
    const clickable = el.closest?.('button, a, [role="button"], .ant-select-selector, .ant-radio-wrapper, .ant-checkbox-wrapper') || el;
    return {
      tag: el.tagName,
      text: shortText(el.innerText || el.textContent || ''),
      value: shortText(el.value || ''),
      placeholder: el.getAttribute?.('placeholder') || '',
      role: el.getAttribute?.('role') || '',
      type: el.getAttribute?.('type') || '',
      label: labelText(el),
      selector: cssPath(el),
      clickableSelector: cssPath(clickable),
      rect: { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) },
    };
  };
  const emit = (type, target, extra = {}) => {
    try {
      window.__codexRecordPaycenterEvent({
        type,
        url: location.href,
        title: document.title,
        target: describe(target),
        bodyHint: shortText(document.body?.innerText || ''),
        extra,
        ts: new Date().toISOString(),
      });
    } catch (err) {}
  };
  document.addEventListener('click', event => emit('click', event.target), true);
  document.addEventListener('change', event => emit('change', event.target), true);
  document.addEventListener('input', event => {
    const target = event.target;
    if (target && ['INPUT', 'TEXTAREA'].includes(target.tagName)) emit('input', target);
  }, true);
}
"""


STOP_BUTTON_JS = r"""
() => {
  if (document.getElementById('__codex_paycenter_stop_recording')) return;
  const button = document.createElement('button');
  button.id = '__codex_paycenter_stop_recording';
  button.textContent = '停止录制';
  button.style.cssText = [
    'position:fixed',
    'z-index:2147483647',
    'top:12px',
    'right:12px',
    'height:36px',
    'padding:0 14px',
    'background:#d92d20',
    'color:white',
    'border:0',
    'border-radius:6px',
    'font-size:14px',
    'font-family:Arial,sans-serif',
    'box-shadow:0 4px 16px rgba(0,0,0,.22)',
    'cursor:pointer',
  ].join(';');
  button.onclick = () => window.__codexStopPaycenterRecording({ ts: new Date().toISOString(), url: location.href });
  document.body.appendChild(button);
}
"""


def install_recorder(frame: Frame) -> None:
    try:
        frame.evaluate(RECORDER_JS)
    except Exception:
        pass


def main() -> None:
    sys.stdout.reconfigure(encoding="utf-8")
    cfg = settings_fixture.__wrapped__()
    phone = os.getenv("E2E_WANZHANGGUI_TENANT_PHONE", cfg.wanzhanggui_tenant_phone)
    password = os.getenv("E2E_WANZHANGGUI_TENANT_PASSWORD", cfg.wanzhanggui_tenant_password)
    out = Path("runtime/manual_records/paycenter") / datetime.now().strftime("%Y%m%d-%H%M%S")
    out.mkdir(parents=True, exist_ok=True)
    events: list[dict[str, Any]] = []
    stopped = Event()

    def record_event(source, payload):
        payload = dict(payload)
        payload["frame_url"] = source["frame"].url
        events.append(payload)
        (out / "events.json").write_text(json.dumps(events, ensure_ascii=False, indent=2), encoding="utf-8")

    def stop_recording(source, payload):
        events.append({"type": "stop", "payload": payload, "frame_url": source["frame"].url})
        stopped.set()

    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False, slow_mo=80)
        context = browser.new_context(viewport={"width": cfg.viewport_width, "height": cfg.viewport_height})
        page = context.new_page()
        page.expose_binding("__codexRecordPaycenterEvent", record_event)
        page.expose_binding("__codexStopPaycenterRecording", stop_recording)
        page.on("framenavigated", lambda frame: install_recorder(frame))

        wzg = WanyoujiFulfillmentPage(page, cfg.tenant_home_url)
        wzg.login_main_account(phone, password)
        page.goto(WANZHANGGUI_CONSOLE_URL, wait_until="domcontentloaded")
        wzg.wait_for_enterprise_console_shell()

        for frame in page.frames:
            install_recorder(frame)
        page.evaluate(STOP_BUTTON_JS)
        (out / "session.json").write_text(
            json.dumps(
                {
                    "phone": phone,
                    "console_url": WANZHANGGUI_CONSOLE_URL,
                    "started_at": datetime.now().isoformat(timespec="seconds"),
                    "note": "手工操作 B-SETTLE-PAYCENTER-001，点击右上角停止录制结束。",
                },
                ensure_ascii=False,
                indent=2,
            ),
            encoding="utf-8",
        )
        print(f"RECORDER_READY {out}", flush=True)

        while not stopped.wait(timeout=1):
            for frame in page.frames:
                install_recorder(frame)
            try:
                page.evaluate(STOP_BUTTON_JS)
            except Exception:
                pass

        for frame in page.frames:
            try:
                events.append(
                    {
                        "type": "final_frame",
                        "frame_url": frame.url,
                        "text": frame.locator("body").inner_text(timeout=1000)[:2000],
                        "ts": datetime.now().isoformat(timespec="seconds"),
                    }
                )
            except Exception:
                pass
        (out / "events.json").write_text(json.dumps(events, ensure_ascii=False, indent=2), encoding="utf-8")
        page.screenshot(path=str(out / "final.png"), full_page=True)
        print(f"RECORDER_SAVED {out}", flush=True)
        context.close()
        browser.close()


if __name__ == "__main__":
    main()
