"""
异常处理和恢复
智能异常处理和自动恢复
"""
from typing import Optional, Callable, List, Dict, Any
from playwright.async_api import Page, Error as PlaywrightError
from loguru import logger
from dataclasses import dataclass
from functools import wraps
import asyncio
import traceback


@dataclass
class RecoveryAction:
    """恢复动作"""
    name: str
    action: Callable
    priority: int = 0


class SmartRecovery:
    """
    智能恢复系统
    检测错误并自动恢复
    """
    
    def __init__(self, page: Page):
        self.page = page
        self._recovery_actions: List[RecoveryAction] = []
        self._error_history: List[Dict[str, Any]] = []
    
    def register_recovery(self, name: str, action: Callable, priority: int = 0):
        """注册恢复动作"""
        recovery = RecoveryAction(name=name, action=action, priority=priority)
        self._recovery_actions.append(recovery)
        self._recovery_actions.sort(key=lambda x: x.priority, reverse=True)
    
    async def attempt_recovery(self, error: Exception) -> bool:
        """
        尝试恢复
        
        Args:
            error: 异常对象
            
        Returns:
            bool: 是否成功恢复
        """
        error_type = type(error).__name__
        error_message = str(error)
        
        # 记录错误
        self._error_history.append({
            "type": error_type,
            "message": error_message,
            "traceback": traceback.format_exc(),
        })
        
        logger.warning(f"尝试恢复: {error_type}: {error_message}")
        
        # 尝试恢复动作
        for recovery in self._recovery_actions:
            try:
                if asyncio.iscoroutinefunction(recovery.action):
                    result = await recovery.action(error)
                else:
                    result = recovery.action(error)
                
                if result:
                    logger.info(f"恢复成功: {recovery.name}")
                    return True
                    
            except Exception as e:
                logger.error(f"恢复动作失败: {recovery.name}, error={e}")
        
        return False
    
    def get_error_history(self) -> List[Dict[str, Any]]:
        """获取错误历史"""
        return self._error_history.copy()


def auto_recovery(max_retries: int = 3, delay: float = 1.0):
    """
    自动恢复装饰器
    
    Args:
        max_retries: 最大重试次数
        delay: 重试延迟
    """
    def decorator(func):
        @wraps(func)
        async def async_wrapper(*args, **kwargs):
            last_error = None
            
            for attempt in range(max_retries):
                try:
                    return await func(*args, **kwargs)
                except Exception as e:
                    last_error = e
                    logger.warning(f"执行失败 (尝试 {attempt + 1}/{max_retries}): {e}")
                    
                    if attempt < max_retries - 1:
                        await asyncio.sleep(delay)
            
            raise last_error
        
        @wraps(func)
        def sync_wrapper(*args, **kwargs):
            import time
            last_error = None
            
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    last_error = e
                    logger.warning(f"执行失败 (尝试 {attempt + 1}/{max_retries}): {e}")
                    
                    if attempt < max_retries - 1:
                        time.sleep(delay)
            
            raise last_error
        
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        return sync_wrapper
    
    return decorator


class ErrorClassifier:
    """
    错误分类器
    分类和处理不同类型的错误
    """
    
    # 错误类型
    NETWORK_ERROR = "network_error"
    ELEMENT_NOT_FOUND = "element_not_found"
    TIMEOUT_ERROR = "timeout_error"
    PERMISSION_ERROR = "permission_error"
    UNKNOWN_ERROR = "unknown_error"
    
    @staticmethod
    def classify(error: Exception) -> str:
        """分类错误"""
        error_type = type(error).__name__
        error_message = str(error).lower()
        
        # 网络错误
        if any(x in error_message for x in ["network", "net::", "connection", "dns"]):
            return ErrorClassifier.NETWORK_ERROR
        
        # 元素未找到
        if any(x in error_message for x in ["not found", "no element", "locator"]):
            return ErrorClassifier.ELEMENT_NOT_FOUND
        
        # 超时
        if any(x in error_message for x in ["timeout", "timed out"]):
            return ErrorClassifier.TIMEOUT_ERROR
        
        # 权限
        if any(x in error_message for x in ["permission", "denied", "forbidden"]):
            return ErrorClassifier.PERMISSION_ERROR
        
        return ErrorClassifier.UNKNOWN_ERROR


class RecoveryStrategies:
    """恢复策略集合"""
    
    @staticmethod
    async def reload_page(page: Page, error: Exception) -> bool:
        """重新加载页面"""
        try:
            await page.reload()
            return True
        except:
            return False
    
    @staticmethod
    async def clear_cookies(page: Page, error: Exception) -> bool:
        """清除Cookies"""
        try:
            await page.context.clear_cookies()
            return True
        except:
            return False
    
    @staticmethod
    async def wait_and_retry(page: Page, error: Exception, wait_time: float = 2.0) -> bool:
        """等待后重试"""
        await asyncio.sleep(wait_time)
        return True
    
    @staticmethod
    async def navigate_home(page: Page, error: Exception) -> bool:
        """导航到首页"""
        try:
            await page.goto("about:blank")
            return True
        except:
            return False


class ErrorHandlerChain:
    """
    错误处理链
    链式处理错误
    """
    
    def __init__(self):
        self._handlers: List[Callable] = []
    
    def add_handler(self, handler: Callable) -> "ErrorHandlerChain":
        """添加处理器"""
        self._handlers.append(handler)
        return self
    
    async def handle(self, error: Exception, context: Dict[str, Any] = None) -> bool:
        """处理错误"""
        context = context or {}
        
        for handler in self._handlers:
            try:
                if asyncio.iscoroutinefunction(handler):
                    result = await handler(error, context)
                else:
                    result = handler(error, context)
                
                if result:
                    return True
                    
            except Exception as e:
                logger.error(f"错误处理器失败: {e}")
        
        return False


class GracefulDegradation:
    """
    优雅降级
    当功能不可用时提供替代方案
    """
    
    def __init__(self):
        self._fallbacks: Dict[str, Callable] = {}
    
    def register_fallback(self, feature: str, fallback: Callable):
        """注册降级方案"""
        self._fallbacks[feature] = fallback
    
    async def execute_with_fallback(
        self,
        feature: str,
        primary: Callable,
        *args,
        **kwargs,
    ) -> Any:
        """
        执行并降级
        
        Args:
            feature: 功能名称
            primary: 主要实现
            *args: 参数
            **kwargs: 关键字参数
            
        Returns:
            Any: 结果
        """
        try:
            if asyncio.iscoroutinefunction(primary):
                return await primary(*args, **kwargs)
            else:
                return primary(*args, **kwargs)
                
        except Exception as e:
            logger.warning(f"主要功能失败: {feature}, 尝试降级")
            
            fallback = self._fallbacks.get(feature)
            if fallback:
                try:
                    if asyncio.iscoroutinefunction(fallback):
                        return await fallback(*args, **kwargs)
                    else:
                        return fallback(*args, **kwargs)
                except Exception as fallback_error:
                    logger.error(f"降级方案失败: {fallback_error}")
            
            raise e
