#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
统一异常处理模块
定义项目专用的异常类型和标准化的重试机制
"""

import time
import logging
from typing import Optional, Callable, Any, Union
from functools import wraps
import os

logger = logging.getLogger(__name__)


class TravelContentCreatorError(Exception):
    """项目基础异常类"""
    
    def __init__(self, message: str, error_code: Optional[str] = None, details: Optional[dict] = None):
        super().__init__(message)
        self.message = message
        self.error_code = error_code
        self.details = details or {}
    
    def __str__(self):
        if self.error_code:
            return f"[{self.error_code}] {self.message}"
        return self.message


class ConfigurationError(TravelContentCreatorError):
    """配置相关异常"""
    pass


class AIModelError(TravelContentCreatorError):
    """AI模型调用异常"""
    pass


class ContentGenerationError(TravelContentCreatorError):
    """内容生成异常"""
    pass


class PosterGenerationError(TravelContentCreatorError):
    """海报生成异常"""
    pass


class ResourceError(TravelContentCreatorError):
    """资源文件异常"""
    pass


class ValidationError(TravelContentCreatorError):
    """数据验证异常"""
    pass


class TimeoutError(TravelContentCreatorError):
    """超时异常"""
    pass


class RetryableError(TravelContentCreatorError):
    """可重试异常"""
    pass


class NonRetryableError(TravelContentCreatorError):
    """不可重试异常"""
    pass


def retry_on_failure(
    max_retries: int = 3,
    delay: float = 1.0,
    backoff: float = 2.0,
    exceptions: tuple = (Exception,),
    non_retryable_exceptions: tuple = (NonRetryableError,)
):
    """
    重试装饰器
    
    Args:
        max_retries: 最大重试次数
        delay: 初始延迟时间（秒）
        backoff: 退避系数
        exceptions: 需要重试的异常类型
        non_retryable_exceptions: 不可重试的异常类型
    """
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            last_exception = None
            current_delay = delay
            
            for attempt in range(max_retries + 1):
                try:
                    return func(*args, **kwargs)
                except non_retryable_exceptions as e:
                    logger.error(f"不可重试异常: {e}")
                    raise
                except exceptions as e:
                    last_exception = e
                    if attempt < max_retries:
                        logger.warning(f"函数 {func.__name__} 第 {attempt + 1} 次调用失败: {e}")
                        logger.info(f"将在 {current_delay:.1f} 秒后重试...")
                        time.sleep(current_delay)
                        current_delay *= backoff
                    else:
                        logger.error(f"函数 {func.__name__} 重试 {max_retries} 次后仍然失败")
                        break
            
            # 如果所有重试都失败了，抛出最后一个异常
            if last_exception:
                raise last_exception
        
        return wrapper
    return decorator


def timeout_handler(timeout_seconds: int):
    """
    超时处理装饰器

    注意: 这个装饰器使用 signal 模块，因此在非Unix-like系统（如Windows）上可能无法正常工作。
    
    Args:
        timeout_seconds: 超时时间（秒）
    """
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            # 在Windows上，signal模块功能有限，以下代码可能无法按预期工作
            if os.name == 'nt':
                logger.warning("timeout_handler在Windows上功能受限，可能无法生效")
                return func(*args, **kwargs)

            import signal
            
            def timeout_signal_handler(signum, frame):
                raise TimeoutError(f"函数 {func.__name__} 执行超时 ({timeout_seconds}秒)")
            
            # 设置超时信号
            old_handler = signal.signal(signal.SIGALRM, timeout_signal_handler)
            signal.alarm(timeout_seconds)
            
            try:
                result = func(*args, **kwargs)
                return result
            finally:
                # 取消超时信号
                signal.alarm(0)
                signal.signal(signal.SIGALRM, old_handler)
        
        return wrapper
    return decorator


def handle_exceptions(
    default_return: Any = None,
    log_level: str = "ERROR",
    reraise: bool = True
):
    """
    通用异常处理装饰器
    
    Args:
        default_return: 异常时的默认返回值
        log_level: 日志级别
        reraise: 是否重新抛出异常
    """
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            try:
                return func(*args, **kwargs)
            except Exception as e:
                # 记录异常
                log_func = getattr(logger, log_level.lower())
                log_func(f"函数 {func.__name__} 发生异常: {e}", exc_info=True)
                
                if reraise:
                    raise
                else:
                    return default_return
        
        return wrapper
    return decorator


class ErrorContext:
    """错误上下文管理器"""
    
    def __init__(self, operation: str, error_type: type = TravelContentCreatorError):
        self.operation = operation
        self.error_type = error_type
        self.start_time = None
    
    def __enter__(self):
        self.start_time = time.time()
        logger.info(f"开始执行操作: {self.operation}")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        duration = time.time() - self.start_time
        
        if exc_type is None:
            logger.info(f"操作完成: {self.operation} (耗时: {duration:.2f}秒)")
        else:
            logger.error(f"操作失败: {self.operation} (耗时: {duration:.2f}秒)")
            
            # 如果是预期的异常类型，包装后重新抛出
            if not isinstance(exc_val, TravelContentCreatorError):
                wrapped_error = self.error_type(
                    f"操作 '{self.operation}' 失败: {str(exc_val)}",
                    details={'original_error': str(exc_val), 'duration': duration}
                )
                raise wrapped_error from exc_val
        
        return False


def validate_required_fields(data: dict, required_fields: list, error_prefix: str = ""):
    """
    验证必需字段
    
    Args:
        data: 要验证的数据字典
        required_fields: 必需字段列表
        error_prefix: 错误消息前缀
    
    Raises:
        ValidationError: 当必需字段缺失时
    """
    missing_fields = []
    for field in required_fields:
        if field not in data or data[field] is None:
            missing_fields.append(field)
    
    if missing_fields:
        error_msg = f"{error_prefix}缺少必需字段: {', '.join(missing_fields)}"
        raise ValidationError(error_msg, error_code="MISSING_REQUIRED_FIELDS")


def safe_execute(func: Callable, *args, **kwargs) -> tuple:
    """
    安全执行函数，返回 (success, result_or_error)
    
    Args:
        func: 要执行的函数
        *args: 函数参数
        **kwargs: 函数关键字参数
    
    Returns:
        tuple: (是否成功, 结果或异常对象)
    """
    try:
        result = func(*args, **kwargs)
        return True, result
    except Exception as e:
        logger.exception(f"函数 {func.__name__} 执行失败")
        return False, e


# 常用的异常实例
COMMON_ERRORS = {
    'config_missing': ConfigurationError("配置文件缺失或格式错误"),
    'api_key_missing': ConfigurationError("API密钥未配置"),
    'model_unavailable': AIModelError("AI模型不可用"),
    'network_error': RetryableError("网络连接错误"),
    'resource_not_found': ResourceError("资源文件未找到"),
    'invalid_format': ValidationError("数据格式无效"),
}


def get_error_by_code(error_code: str) -> TravelContentCreatorError:
    """根据错误代码获取预定义的异常对象"""
    return COMMON_ERRORS.get(error_code, TravelContentCreatorError(f"未知错误: {error_code}")) 