"""
弹窗自动关闭处理器
自动识别并关闭各类弹窗（登录弹窗、广告弹窗、Cookie提示等）
"""
import asyncio
from typing import Optional, List, Callable
from playwright.async_api import Page
from loguru import logger


class PopupHandler:
    """
    弹窗处理器
    自动识别并关闭各类弹窗
    """

    # 常见弹窗关闭按钮选择器模式
    CLOSE_BUTTON_PATTERNS = [
        # 通用关闭按钮
        "[class*='close']",
        "[class*='Close']",
        "[class*='dismiss']",
        "[class*='cancel']",
        "[aria-label*='关闭']",
        "[aria-label*='close']",
        "[aria-label*='Close']",
        "[title*='关闭']",
        "[title*='close']",
        "button.close",
        ".close-btn",
        ".close-btn",
        ".modal-close",
        ".dialog-close",
        ".popup-close",
        "a.close",
        "span.close",

        # 图标类关闭按钮
        "[class*='icon-close']",
        "[class*='icon-close']",
        "[class*='IconClose']",
        "svg[class*='close']",
        "i[class*='close']",

        # 登录弹窗
        "[class*='login'] [class*='close']",
        "[class*='Login'] [class*='close']",
        ".login-modal .close",
        ".login-dialog .close",

        # X 按钮
        "button[aria-label='×']",
        "button[aria-label='x']",
        "a[aria-label='×']",
        ".x-btn",
        ".btn-x",
    ]

    # 关闭按钮文本模式（中文）
    CLOSE_TEXTS_CN = [
        "关闭",
        "取消",
        "跳过",
        "暂不登录",
        "稍后再说",
        "以后再说",
        "暂不注册",
        "我知道了",
        "不再提示",
        "×",
        "✕",
        "✖",
    ]

    # 关闭按钮文本模式（英文）
    CLOSE_TEXTS_EN = [
        "Close",
        "Cancel",
        "Skip",
        "Later",
        "Not now",
        "No thanks",
        "Dismiss",
        "×",
        "x",
    ]

    # 常见弹窗容器选择器
    POPUP_CONTAINERS = [
        # 模态框
        "[class*='modal']",
        "[class*='Modal']",
        "[class*='dialog']",
        "[class*='Dialog']",
        "[class*='popup']",
        "[class*='Popup']",
        "[role='dialog']",
        "[role='alertdialog']",

        # 登录弹窗
        "[class*='login-modal']",
        "[class*='LoginModal']",
        "[class*='login-dialog']",
        "[class*='LoginDialog']",

        # Cookie提示
        "[class*='cookie']",
        "[class*='Cookie']",

        # 广告弹窗
        "[class*='advertisement']",
        "[class*='ads-popup']",
    ]

    def __init__(self, page: Page):
        self.page = page
        self._closed_popups: List[str] = []

    async def detect_and_close(self) -> bool:
        """
        检测并关闭弹窗

        Returns:
            bool: 是否成功关闭弹窗
        """
        try:
            # 等待页面稳定
            await asyncio.sleep(0.5)

            # 方法1: 尝试通过选择器关闭
            if await self._close_by_selector():
                return True

            # 方法2: 尝试通过文本关闭
            if await self._close_by_text():
                return True

            # 方法3: 尝试按 ESC 键关闭
            if await self._close_by_esc():
                return True

            return False

        except Exception as e:
            logger.debug(f"弹窗检测失败: {e}")
            return False

    async def _close_by_selector(self) -> bool:
        """通过选择器关闭弹窗"""
        for selector in self.CLOSE_BUTTON_PATTERNS:
            try:
                elements = await self.page.locator(selector).all()
                for elem in elements:
                    if await elem.is_visible():
                        # 检查是否在弹窗容器内
                        parent_html = await elem.evaluate(
                            "el => el.closest('[class*=\\'modal\\'], [class*=\\'dialog\\'], [class*=\\'popup\\'], [role=\\'dialog\\']')"
                        )

                        # 如果是关闭按钮或在弹窗内，点击关闭
                        if parent_html or 'close' in selector.lower():
                            await elem.click(timeout=1000)
                            logger.info(f"已关闭弹窗: {selector}")
                            await asyncio.sleep(0.3)
                            return True
            except:
                continue

        return False

    async def _close_by_text(self) -> bool:
        """通过文本关闭弹窗"""
        all_texts = self.CLOSE_TEXTS_CN + self.CLOSE_TEXTS_EN

        for text in all_texts:
            try:
                # 尝试精确匹配
                locator = self.page.get_by_text(text, exact=True)
                if await locator.is_visible():
                    await locator.click(timeout=1000)
                    logger.info(f"已关闭弹窗: 文本 '{text}'")
                    await asyncio.sleep(0.3)
                    return True
            except:
                continue

        return False

    async def _close_by_esc(self) -> bool:
        """通过 ESC 键关闭弹窗"""
        try:
            # 检查是否有可见的弹窗
            for container in self.POPUP_CONTAINERS:
                if await self.page.locator(container).is_visible():
                    await self.page.keyboard.press("Escape")
                    logger.info("已通过 ESC 键关闭弹窗")
                    await asyncio.sleep(0.3)
                    return True
        except:
            pass

        return False

    async def close_login_popup(self) -> bool:
        """
        专门关闭登录弹窗

        Returns:
            bool: 是否成功关闭
        """
        # 登录弹窗特定的关闭策略
        login_close_selectors = [
            # 小红书
            ".login-container .close-btn",
            ".login-modal .close",
            "[class*='login'] [class*='close']",

            # 通用
            ".login-dialog .close",
            ".auth-modal .close",
            "button[class*='close']",

            # 文本关闭
            "text=暂不登录",
            "text=跳过",
            "text=稍后再说",
        ]

        for selector in login_close_selectors:
            try:
                locator = self.page.locator(selector)
                if await locator.is_visible():
                    await locator.click(timeout=1000)
                    logger.info(f"已关闭登录弹窗: {selector}")
                    return True
            except:
                continue

        return False

    async def close_cookie_popup(self) -> bool:
        """
        关闭 Cookie 提示弹窗

        Returns:
            bool: 是否成功关闭
        """
        cookie_close_selectors = [
            # 通用 Cookie 弹窗
            "[class*='cookie'] button",
            "[class*='Cookie'] button",
            "button[class*='accept']",
            "button[class*='reject']",

            # 文本
            "text=接受",
            "text=拒绝",
            "text=同意",
            "text=Accept",
            "text=Reject",
        ]

        for selector in cookie_close_selectors:
            try:
                locator = self.page.locator(selector)
                if await locator.is_visible():
                    await locator.click(timeout=1000)
                    logger.info(f"已关闭 Cookie 弹窗: {selector}")
                    return True
            except:
                continue

        return False

    async def wait_and_close(
        self,
        timeout: float = 5.0,
        check_interval: float = 0.5
    ) -> bool:
        """
        等待弹窗出现并关闭

        Args:
            timeout: 超时时间
            check_interval: 检查间隔

        Returns:
            bool: 是否成功关闭
        """
        start_time = asyncio.get_event_loop().time()

        while asyncio.get_event_loop().time() - start_time < timeout:
            if await self.detect_and_close():
                return True
            await asyncio.sleep(check_interval)

        return False


async def auto_close_popup(page: Page, timeout: float = 5.0) -> bool:
    """
    自动关闭弹窗的便捷函数

    Args:
        page: 页面对象
        timeout: 超时时间

    Returns:
        bool: 是否成功关闭
    """
    handler = PopupHandler(page)
    return await handler.wait_and_close(timeout)


async def smart_close_popup(page: Page) -> bool:
    """
    智能关闭弹窗
    尝试多种策略关闭弹窗

    Args:
        page: 页面对象

    Returns:
        bool: 是否成功关闭
    """
    handler = PopupHandler(page)

    # 依次尝试不同策略
    strategies = [
        handler.close_login_popup,
        handler.close_cookie_popup,
        handler.detect_and_close,
    ]

    for strategy in strategies:
        try:
            if await strategy():
                return True
        except:
            continue

    return False
