"""
自动修复器
自动修复失败的元素定位
"""
import re
from typing import Optional, Dict, List
from playwright.async_api import Page
from loguru import logger


class AutoHealer:
    """
    自动修复器
    自动修复失败的元素定位
    """

    def __init__(self, page: Page):
        self.page = page
        self._selector_history: Dict[str, List[str]] = {}
        self._healed_count = 0

    def record_success(self, name: str, selector: str):
        """记录成功的选择器"""
        if name not in self._selector_history:
            self._selector_history[name] = []
        self._selector_history[name].append(selector)

    async def heal_selector(self, name: str, failed_selector: str) -> Optional[str]:
        """
        尝试修复选择器

        Args:
            name: 元素名称
            failed_selector: 失败的选择器

        Returns:
            Optional[str]: 修复后的选择器
        """
        # 1. 尝试历史选择器
        if name in self._selector_history:
            for selector in reversed(self._selector_history[name]):
                if selector != failed_selector:
                    try:
                        locator = self.page.locator(selector)
                        if await locator.count() > 0:
                            logger.info(f"使用历史选择器修复: {selector}")
                            self._healed_count += 1
                            return selector
                    except:
                        continue

        # 2. 尝试相似选择器
        similar_selectors = self._generate_similar_selectors(failed_selector)
        for selector in similar_selectors:
            try:
                locator = self.page.locator(selector)
                if await locator.count() > 0:
                    logger.info(f"使用相似选择器修复: {selector}")
                    self._healed_count += 1
                    return selector
            except:
                continue

        # 3. 尝试智能查找
        healed = await self._smart_heal(failed_selector)
        if healed:
            self._healed_count += 1
            return healed

        return None

    def _generate_similar_selectors(self, selector: str) -> List[str]:
        """生成相似选择器"""
        similar = []

        # ID选择器 -> class选择器
        if selector.startswith('#'):
            similar.append(selector.replace('#', '.'))

        # class选择器 -> ID选择器
        if selector.startswith('.'):
            similar.append(selector.replace('.', '#'))

        # 添加通配符
        if '[' in selector and '=' in selector:
            similar.append(selector.replace('=', '*='))

        # 移除nth-child
        similar.append(re.sub(r':nth-child\([^)]+\)', '', selector))

        # 父子关系转后代关系
        similar.append(selector.replace(' > ', ' '))

        # 移除最后一个类
        if selector.count('.') > 1:
            parts = selector.rsplit('.', 1)
            similar.append(parts[0])

        return similar

    async def _smart_heal(self, failed_selector: str) -> Optional[str]:
        """智能修复"""
        # 提取选择器中的文本信息
        text_match = re.search(r":has-text\(['\"]([^'\"]+)['\"]\)", failed_selector)
        if text_match:
            text = text_match.group(1)
            # 尝试用文本直接查找
            locator = self.page.get_by_text(text)
            if await locator.count() > 0:
                return f"text={text}"

        # 提取属性信息
        attr_match = re.search(r"\[([a-z-]+)['\"]?=['\"]?([^'\"\]]+)", failed_selector)
        if attr_match:
            attr_name = attr_match.group(1)
            attr_value = attr_match.group(2)
            # 尝试模糊匹配
            locator = self.page.locator(f"[{attr_name}*='{attr_value}']")
            if await locator.count() > 0:
                return f"[{attr_name}*='{attr_value}']"

        return None

    def get_stats(self) -> Dict[str, int]:
        """获取修复统计"""
        return {
            'healed_count': self._healed_count,
            'history_size': sum(len(v) for v in self._selector_history.values()),
            'tracked_elements': len(self._selector_history),
        }

    def clear_history(self):
        """清空历史记录"""
        self._selector_history.clear()

    async def heal_and_execute(
        self,
        selector: str,
        action: str,
        value: str = None,
        max_attempts: int = 3,
    ) -> bool:
        """
        修复选择器并执行操作

        Args:
            selector: 原始选择器
            action: 操作类型 (click, fill, etc.)
            value: 操作值
            max_attempts: 最大尝试次数

        Returns:
            bool: 是否成功
        """
        current_selector = selector

        for attempt in range(max_attempts):
            try:
                locator = self.page.locator(current_selector)

                if action == 'click':
                    await locator.click()
                elif action == 'fill' and value:
                    await locator.fill(value)
                elif action == 'type' and value:
                    await locator.type(value)
                elif action == 'check':
                    await locator.check()

                # 记录成功
                self.record_success(f"auto_{action}", current_selector)
                return True

            except Exception as e:
                logger.warning(f"尝试 {attempt + 1} 失败: {e}")

                # 尝试修复
                healed = await self.heal_selector(f"auto_{attempt}", current_selector)
                if healed:
                    current_selector = healed

        return False
