from __future__ import annotations

from typing import Any, Optional, Tuple

from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.ui import WebDriverWait


def 等待任意元素可点击(
    驱动器对象: Any,
    元素列表: list[tuple[str, str]],
    超时时间: int | float = 30,
) -> Optional[Tuple[int, WebElement]]:
    """
    等待一组元素中任意一个达到“可点击”状态，并返回对应元素信息。

    本函数适用于页面流程存在多种可能分支的场景，例如：
    登录成功按钮、错误提示按钮、验证码按钮等可能先后出现，
    脚本只需要捕获第一个可点击元素即可继续后续逻辑。

    函数会在给定时间内持续轮询 `元素列表` 中的所有定位信息，
    一旦某个元素满足“可见且可点击”条件，立即返回。

    Args:
        驱动器对象 (Any):
            Selenium 浏览器驱动对象。

        元素列表 (list[tuple[str, str]]):
            元素定位信息列表，每个元素为 `(定位方法, 定位值)`。
            例如：
                [
                    ("XPATH", "//button[@id='login']"),
                    ("CSS_SELECTOR", "button.verify"),
                    ("ID", "submit"),
                ]

        超时时间 (int | float, optional):
            最大等待时间（秒），默认 30 秒。

    Returns:
        Optional[Tuple[int, WebElement]]:
            成功时返回 `(索引, 元素对象)`：
                - 索引：表示命中的元素在 `元素列表` 中的位置
                - 元素对象：对应的 WebElement

            若等待超时或发生异常，则返回 None。

    Notes:
        - 本函数属于“任意匹配”等待模式，一旦检测到某个元素满足
          条件，等待立即结束。
        - 内部使用 Selenium 显式等待轮询机制实现。
    """
    try:
        if 驱动器对象 is None:
            return None

        if not isinstance(元素列表, list) or not 元素列表:
            return None

        if not isinstance(超时时间, (int, float)) or 超时时间 <= 0:
            return None

        def _检查任意元素(driver):
            for 索引, (定位方法, 定位值) in enumerate(元素列表):
                try:
                    by = getattr(By, 定位方法.upper(), None)
                    if by is None:
                        continue

                    元素 = driver.find_element(by, 定位值)

                    if 元素.is_displayed() and 元素.is_enabled():
                        return (索引, 元素)

                except Exception:
                    continue

            return False

        return WebDriverWait(驱动器对象, 超时时间).until(_检查任意元素)

    except Exception:
        return None