import os
import allure
from playwright.sync_api import Page, Locator, expect


class BasePage:
    """公共页面基类：封装稳定等待、截图、候选定位器选择等通用能力。"""

    def __init__(self, page: Page, screenshot_dir: str):
        self.page = page
        self.screenshot_dir = screenshot_dir
        os.makedirs(self.screenshot_dir, exist_ok=True)

    def goto(self, url: str):
        self.page.goto(url, wait_until="domcontentloaded")
        try:
            self.page.wait_for_load_state("networkidle", timeout=5000)
        except Exception:
            pass

    def screenshot(self, name: str) -> str:
        path = os.path.join(self.screenshot_dir, name)
        self.page.screenshot(path=path, full_page=True)
        allure.attach.file(path, name=name, attachment_type=allure.attachment_type.PNG)
        return path

    def first_visible_locator(
        self,
        selectors: list[str],
        timeout: int = 5000,
        description: str = "元素",
    ) -> Locator:
        """
        从候选 CSS/XPath/Text selector 中返回第一个可见元素。
        注意：页面侦察结果为空时，候选 selector 需在项目落地时根据真实 DOM 调整。
        """
        last_error = None
        for selector in selectors:
            try:
                locator = self.page.locator(selector).first
                locator.wait_for(state="visible", timeout=timeout)
                return locator
            except Exception as exc:
                last_error = exc

        self.screenshot(f"not_found_{description}.png")
        raise AssertionError(f"未找到可见{description}，请根据真实页面 DOM 更新 selector。候选：{selectors}") from last_error

    def click_first_visible(
        self,
        selectors: list[str],
        timeout: int = 5000,
        description: str = "按钮",
    ):
        locator = self.first_visible_locator(selectors, timeout=timeout, description=description)
        locator.click()

    def fill_first_visible(
        self,
        selectors: list[str],
        value: str,
        timeout: int = 5000,
        description: str = "输入框",
    ):
        locator = self.first_visible_locator(selectors, timeout=timeout, description=description)
        locator.fill(value)

    def wait_network_idle(self):
        try:
            self.page.wait_for_load_state("networkidle", timeout=5000)
        except Exception:
            pass

    def assert_url_contains(self, expected_part: str):
        expect(self.page).to_have_url(lambda url: expected_part in url)

    def wait_for_timeout(self, ms: int):
        self.page.wait_for_timeout(ms)
