import re
from playwright.sync_api import expect
from zhyy.test_case.Resource.UI.base_page import BasePage


class SmartManagementLoginPage(BasePage):
    """
    智慧运营登录页对象。

    TODO:
    当前未提供登录页侦察结果，以下 selector 为常见候选。
    落地时请优先使用真实 DOM 中稳定属性，例如 data-testid、id、name。
    """

    USERNAME_INPUT_SELECTORS = [
        "input[name='username']",
        "input[name='userName']",
        "input[id*='username']",
        "input[placeholder*='用户名']",
        "input[placeholder*='账号']",
    ]

    PASSWORD_INPUT_SELECTORS = [
        "input[name='password']",
        "input[type='password']",
        "input[placeholder*='密码']",
    ]

    LOGIN_BUTTON_SELECTORS = [
        "button:has-text('登录')",
        "button:has-text('登 录')",
        "[role='button']:has-text('登录')",
    ]

    def login_if_needed(self, username: str, password: str):
        """
        如果当前页面出现登录表单则登录；如果已登录或 SSO 已生效则跳过。
        """
        username_input = self.page.locator(",".join(self.USERNAME_INPUT_SELECTORS)).first
        try:
            username_input.wait_for(state="visible", timeout=5000)
        except Exception:
            return

        self.fill_first_visible(self.USERNAME_INPUT_SELECTORS, username, description="用户名输入框")
        self.fill_first_visible(self.PASSWORD_INPUT_SELECTORS, password, description="密码输入框")
        self.click_first_visible(self.LOGIN_BUTTON_SELECTORS, description="登录按钮")
        self.wait_network_idle()
        self.screenshot("after_login.png")


class ContractManagePage(BasePage):
    """
    合同管理页面对象。

    被测页面：
    https://smart-management-web-st.best-envision.com/SZPurchase/PurchaseManage/PurchaseOrderManage

    TODO:
    reconnaissanceResult 为空，缺少真实 DOM。
    以下 selector 采用“清晰候选 + TODO”方式，落地执行前需通过页面侦察结果替换为真实稳定 selector。
    """

    CONTRACT_MENU_SELECTORS = [
        # TODO: 使用真实菜单 DOM 替换，例如 [data-testid='contract-menu']
        "text=合同管理",
        "a:has-text('合同管理')",
        "li:has-text('合同管理')",
        "[role='menuitem']:has-text('合同管理')",
    ]

    CONTRACT_NO_INPUT_SELECTORS = [
        # TODO: 使用真实合同编号输入框 selector 替换
        "input[placeholder*='合同编号']",
        "input[aria-label*='合同编号']",
        ".ant-form-item:has-text('合同编号') input",
        ".el-form-item:has-text('合同编号') input",
        "label:has-text('合同编号') + div input",
    ]

    QUERY_BUTTON_SELECTORS = [
        "button:has-text('查询')",
        "button:has-text('搜索')",
        "[role='button']:has-text('查询')",
        "[role='button']:has-text('搜索')",
    ]

    TABLE_ROW_SELECTORS = [
        # Ant Design Table
        ".ant-table-tbody > tr:not(.ant-table-placeholder)",
        # Element Plus / Element UI Table
        ".el-table__body tbody tr",
        # 原生 table
        "table tbody tr",
    ]

    EMPTY_SELECTORS = [
        ".ant-empty",
        ".el-empty",
        "text=暂无数据",
        "text=无数据",
        "text=No Data",
    ]

    def open(self, url: str):
        self.goto(url)
        self.screenshot("contract_manage_opened.png")

    def open_contract_menu_if_visible(self):
        """
        用户步骤要求“找到合同菜单”。
        如果当前 URL 已直达合同管理页，则菜单可能无需点击。
        若菜单可见则点击；不可见不强制失败，避免直达 URL 场景误报。
        """
        for selector in self.CONTRACT_MENU_SELECTORS:
            locator = self.page.locator(selector).first
            try:
                locator.wait_for(state="visible", timeout=2000)
                locator.click()
                self.wait_network_idle()
                self.screenshot("contract_menu_clicked.png")
                return
            except Exception:
                continue

    def search_by_contract_no_keyword(self, keyword: str):
        self.fill_first_visible(
            self.CONTRACT_NO_INPUT_SELECTORS,
            keyword,
            description="合同编号搜索框",
        )
        self.click_first_visible(
            self.QUERY_BUTTON_SELECTORS,
            description="查询按钮",
        )
        self.wait_network_idle()
        self.wait_for_timeout(1000)
        self.screenshot("contract_no_search_result.png")

    def _table_rows_locator(self):
        for selector in self.TABLE_ROW_SELECTORS:
            rows = self.page.locator(selector)
            try:
                if rows.count() > 0 and rows.first.is_visible(timeout=2000):
                    return rows
            except Exception:
                continue
        return None

    def has_empty_result(self) -> bool:
        for selector in self.EMPTY_SELECTORS:
            try:
                locator = self.page.locator(selector).first
                if locator.is_visible(timeout=1000):
                    return True
            except Exception:
                continue
        return False

    def get_result_row_texts(self) -> list[str]:
        rows = self._table_rows_locator()
        if rows is None:
            return []

        row_texts = []
        count = rows.count()
        for index in range(count):
            row = rows.nth(index)
            text = re.sub(r"\s+", " ", row.inner_text()).strip()
            if text:
                row_texts.append(text)
        return row_texts

    def assert_contract_no_fuzzy_match(self, keyword: str):
        """
        断言查询结果与合同编号模糊匹配条件一致。

        说明：
        由于缺少真实表格列 selector，当前按整行文本包含 keyword 断言。
        落地后建议替换为“合同编号列单元格”精确读取：
        - AntD: 根据 th 文本定位列 index，再读取 tbody tr td[index]
        - Element: 使用列 prop 或 class 定位
        """
        row_texts = self.get_result_row_texts()

        assert row_texts, (
            f"合同编号关键字【{keyword}】查询后未获取到表格数据。"
            f"若业务允许无结果，请调整测试数据为存在的合同编号片段。"
        )

        unmatched_rows = [text for text in row_texts if keyword not in text]
        assert not unmatched_rows, (
            f"存在与合同编号关键字【{keyword}】不匹配的查询结果：{unmatched_rows}"
        )
