from __future__ import annotations

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

from playwright.sync_api import Response, sync_playwright

sys.path.insert(0, os.getcwd())

from e2e.conftest import settings as settings_fixture
from e2e.pages.wanzhanggui_order_page import WanyoujiFulfillmentPage
from e2e.utils.account_store import E2EAccount, account_store
from e2e.utils.bug_reporter import BugReporter


SUSPICIOUS_KEYWORDS = [
    "异常",
    "请求异常",
    "接口异常",
    "失败",
    "错误",
    "error",
    "exception",
    "fail",
    "message",
    "msg",
]


def resolve_wanyouji_account() -> E2EAccount:
    explicit_phone = (
        os.getenv("E2E_SETTLE_WANYOUJI_PHONE", "").strip()
        or os.getenv("E2E_TASK_WANYOUJI_PHONE", "").strip()
    )
    store = account_store()
    accounts = store.load()
    if explicit_phone:
        account = next((item for item in accounts if item.phone == explicit_phone), None)
        assert account is not None, f"runtime/e2e_accounts.json not found account: {explicit_phone}"
        return account

    payload = store.load_payload()
    orders = sorted(
        payload.get("dispatched_orders", []),
        key=lambda item: item.get("updated_at", item.get("created_at", "")),
        reverse=True,
    )
    for order in orders:
        for phone in [order.get("task_wanyouji_phone"), order.get("wanyouji_phone")]:
            if not phone:
                continue
            account = next((item for item in accounts if item.phone == phone), None)
            if account:
                return account

    candidates = [
        item
        for item in accounts
        if item.account_type == "main"
        and item.wanyouji_status == "opened"
        and item.certification_status == "approved"
    ]
    assert candidates, "No available Wanyouji main account found."
    return sorted(candidates, key=lambda item: item.updated_at, reverse=True)[0]


def safe_response_text(response: Response) -> str:
    try:
        text = response.text()
    except Exception as exc:
        return f"<read response failed: {exc}>"
    return text[:5000]


def collect_response(response: Response, records: list[dict[str, Any]]) -> None:
    request = response.request
    if request.resource_type not in {"xhr", "fetch"}:
        return
    body = safe_response_text(response)
    post_data = ""
    try:
        post_data = request.post_data or ""
    except Exception:
        post_data = ""
    records.append(
        {
            "time": datetime.now().isoformat(timespec="milliseconds"),
            "status": response.status,
            "method": request.method,
            "resource_type": request.resource_type,
            "url": response.url,
            "request_body": post_data[:3000],
            "response_body": body,
            "suspicious": response.status >= 400
            or any(keyword.lower() in body.lower() for keyword in SUSPICIOUS_KEYWORDS),
        }
    )


def main() -> None:
    sys.stdout.reconfigure(encoding="utf-8")
    settings = settings_fixture.__wrapped__()
    account = resolve_wanyouji_account()
    run_dir = Path("runtime/probes/wanyouji_settlement_bill_list_network") / datetime.now().strftime(
        "%Y%m%d-%H%M%S"
    )
    run_dir.mkdir(parents=True, exist_ok=True)

    records: list[dict[str, Any]] = []
    console_messages: list[dict[str, str]] = []

    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(headless=False)
        context = browser.new_context(
            viewport={"width": settings.viewport_width, "height": settings.viewport_height}
        )
        page = context.new_page()
        page.on("response", lambda response: collect_response(response, records))
        page.on(
            "console",
            lambda message: console_messages.append(
                {
                    "time": datetime.now().isoformat(timespec="milliseconds"),
                    "type": message.type,
                    "text": message.text,
                }
            ),
        )

        bug_reporter = BugReporter(page, case_id="WYJ-SETTLE-BILL-LIST-PROBE")
        owner_page = WanyoujiFulfillmentPage(page, settings.tenant_home_url, bug_reporter)
        owner_page.login_main_account(account.phone, account.password)

        records.clear()
        console_messages.clear()
        frame = owner_page.open_workshop_settlement_bill_list()
        page.wait_for_timeout(6000)

        body_text = page.locator("body").inner_text(timeout=5000)
        frame_text = frame.locator("body").inner_text(timeout=5000)
        snapshot = {
            "account": account.phone,
            "page_url": page.url,
            "frame_url": frame.url,
            "frames": [item.url for item in page.frames],
            "body_text": body_text,
            "frame_text": frame_text,
            "suspicious_count": sum(1 for item in records if item.get("suspicious")),
        }

        (run_dir / "network.json").write_text(
            json.dumps(records, ensure_ascii=False, indent=2), encoding="utf-8"
        )
        (run_dir / "console.json").write_text(
            json.dumps(console_messages, ensure_ascii=False, indent=2), encoding="utf-8"
        )
        (run_dir / "snapshot.json").write_text(
            json.dumps(snapshot, ensure_ascii=False, indent=2), encoding="utf-8"
        )
        page.screenshot(path=str(run_dir / "page.png"), full_page=True)

        suspicious = [item for item in records if item.get("suspicious")]
        print(f"Probe done: {run_dir}")
        print(f"Account: {account.phone}")
        print(f"XHR/fetch count: {len(records)}; suspicious count: {len(suspicious)}")
        for item in suspicious[:10]:
            print(f"- {item['status']} {item['method']} {item['url']}")
            print(f"  request: {item['request_body'][:300] or '<empty>'}")
            print(f"  response: {item['response_body'][:500] or '<empty>'}")

        context.close()
        browser.close()


if __name__ == "__main__":
    main()
