from __future__ import annotations

import argparse
import os
import sys
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path

from dotenv import load_dotenv
from playwright.sync_api import Browser, BrowserContext, Page, Playwright, sync_playwright

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

from e2e.pages.tenant_auth_page import TenantAuthPage
from e2e.pages.wanzhanggui_order_page import WANYOUJI_CONSOLE_URL
from e2e.pages.wanzhanggui_push_page import WANZHANGGUI_CONSOLE_URL
from e2e.utils.account_store import E2EAccount, account_store


TENANT_HOME_URL = "https://test-lianlianyun.lianlianwz.com/home"
OUT_ROOT = Path("runtime/probes/dual_browser_tenant_login")


@dataclass(frozen=True)
class LoginTarget:
    role: str
    channel: str
    phone: str
    password: str
    console_url: str


def choose_wanyouji_account(wanzhanggui_phone: str) -> E2EAccount:
    store = account_store()

    explicit_phone = os.getenv("E2E_DUAL_BROWSER_WANYOUJI_PHONE", "").strip()
    if explicit_phone:
        account = store.find(phone=explicit_phone)
        if not account:
            raise AssertionError(f"E2E_DUAL_BROWSER_WANYOUJI_PHONE not found in ledger: {explicit_phone}")
        return account

    candidates = []
    for account in store.load():
        if account.certification_status != "approved" or account.wanyouji_status != "opened":
            continue
        bound = account.bound_wanzhanggui_enterprise == wanzhanggui_phone or any(
            item.get("phone") == wanzhanggui_phone for item in account.wanzhanggui_bindings
        )
        authorized = any(
            item.get("wanzhanggui_phone") == wanzhanggui_phone and item.get("status") == "authorized"
            for item in account.workshop_authorizations
        )
        if bound or authorized:
            candidates.append(account)

    if candidates:
        return sorted(candidates, key=lambda account: account.updated_at, reverse=True)[0]

    fallback = store.find_wanyouji_owner_for_member()
    if fallback:
        return fallback
    raise AssertionError("No opened Wanyouji account found in runtime/e2e_accounts.json")


def build_targets() -> tuple[LoginTarget, LoginTarget]:
    wanzhanggui_phone = os.getenv("E2E_DUAL_BROWSER_WANZHANGGUI_PHONE", "").strip() or os.getenv(
        "E2E_WANZHANGGUI_TENANT_PHONE", "19147509308"
    )
    wanzhanggui_password = os.getenv("E2E_DUAL_BROWSER_WANZHANGGUI_PASSWORD", "").strip() or os.getenv(
        "E2E_WANZHANGGUI_TENANT_PASSWORD", "test123456"
    )
    wanyouji = choose_wanyouji_account(wanzhanggui_phone)

    return (
        LoginTarget(
            role="wanyouji",
            channel="chrome",
            phone=wanyouji.phone,
            password=os.getenv("E2E_DUAL_BROWSER_WANYOUJI_PASSWORD", "").strip() or wanyouji.password,
            console_url=WANYOUJI_CONSOLE_URL,
        ),
        LoginTarget(
            role="wanzhanggui",
            channel="chrome",
            phone=wanzhanggui_phone,
            password=wanzhanggui_password,
            console_url=WANZHANGGUI_CONSOLE_URL,
        ),
    )


def launch_channel(playwright: Playwright, channel: str, headed: bool, slow_mo: int) -> Browser:
    return playwright.chromium.launch(
        channel=channel,
        headless=not headed,
        slow_mo=slow_mo,
        args=["--window-size=1440,900"],
    )


def write_probe_artifacts(page: Page, target: LoginTarget, out_dir: Path) -> None:
    role_dir = out_dir / target.role
    role_dir.mkdir(parents=True, exist_ok=True)
    body_text = page.locator("body").inner_text(timeout=5000)
    (role_dir / "body.txt").write_text(body_text, encoding="utf-8")
    (role_dir / "frames.txt").write_text("\n".join(frame.url for frame in page.frames), encoding="utf-8")
    page.screenshot(path=role_dir / "console.png", full_page=True)


def login_and_verify(browser: Browser, target: LoginTarget, out_dir: Path) -> BrowserContext:
    context = browser.new_context(viewport={"width": 1440, "height": 900}, screen={"width": 1440, "height": 900})
    page = context.new_page()
    setattr(page, "_e2e_dual_browser_role", target.role)
    setattr(page, "_e2e_dual_browser_channel", target.channel)

    tenant_page = TenantAuthPage(page, TENANT_HOME_URL)
    tenant_page.login_main_account(target.phone, target.password)
    page.goto(target.console_url, wait_until="domcontentloaded")
    tenant_page.wait_for_enterprise_console_shell()
    page.wait_for_timeout(1500)
    write_probe_artifacts(page, target, out_dir)
    return context


def main() -> None:
    load_dotenv()
    parser = argparse.ArgumentParser(description="Verify separate visible Chrome windows can hold isolated tenant logins.")
    parser.add_argument("--headed", action="store_true", help="Run visible Chrome windows. Kept for compatibility; this is now the default.")
    parser.add_argument("--headless", action="store_true", help="Run without visible browser windows.")
    parser.add_argument("--hold-seconds", type=int, default=0, help="Keep both browsers open after login.")
    parser.add_argument("--slow-mo", type=int, default=200, help="Playwright slow_mo in milliseconds.")
    args = parser.parse_args()

    timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
    out_dir = OUT_ROOT / timestamp
    out_dir.mkdir(parents=True, exist_ok=True)
    wanyouji_target, wanzhanggui_target = build_targets()

    contexts: list[BrowserContext] = []
    browser: Browser | None = None
    try:
        with sync_playwright() as playwright:
            browser = launch_channel(playwright, "chrome", headed=not args.headless, slow_mo=args.slow_mo)
            for target in [wanyouji_target, wanzhanggui_target]:
                print(f"[dual-browser] login role={target.role} channel={target.channel} phone={target.phone}")
                contexts.append(
                    login_and_verify(
                        browser,
                        target,
                        out_dir=out_dir,
                    )
                )
            summary = "\n".join(
                [
                    f"wanyouji: channel={wanyouji_target.channel}, phone={wanyouji_target.phone}",
                    f"wanzhanggui: channel={wanzhanggui_target.channel}, phone={wanzhanggui_target.phone}",
                    f"artifacts: {out_dir}",
                ]
            )
            (out_dir / "summary.txt").write_text(summary, encoding="utf-8")
            print(summary)
            if args.hold_seconds > 0:
                print(f"[dual-browser] holding browsers for {args.hold_seconds}s")
                contexts[0].pages[0].wait_for_timeout(args.hold_seconds * 1000)
    finally:
        for context in reversed(contexts):
            try:
                context.close()
            except Exception:
                pass
        if browser is not None:
            try:
                browser.close()
            except Exception:
                pass


if __name__ == "__main__":
    main()
