"""
Symphra Excel库的异常类和异常处理工具

提供统一的异常定义、异常处理装饰器和上下文管理器，
用于简化错误处理并提供一致的错误信息。
"""

import functools
import logging
from contextlib import contextmanager
from typing import Any, Callable, Generator, TypeVar

# 配置日志
logger = logging.getLogger(__name__)

# 类型变量
T = TypeVar("T")
F = TypeVar("F", bound=Callable[..., Any])


# ==================== 异常类 ====================


class SymphraExcelError(Exception):
    """Symphra Excel库的基础异常类"""

    def __init__(self, message: str, details: Any | None = None) -> None:
        super().__init__(message)
        self.message = message
        self.details = details

    def __str__(self) -> str:
        if self.details:
            return f"{self.message} (详细信息: {self.details})"
        return self.message


class FileFormatError(SymphraExcelError):
    """当Excel文件格式出现问题时引发此异常"""

    pass


class TemplateError(SymphraExcelError):
    """当模板处理出现问题时引发此异常"""

    pass


class StyleError(SymphraExcelError):
    """当单元格样式出现问题时引发此异常"""

    pass


class ValidationError(SymphraExcelError):
    """当验证错误时引发此异常"""

    pass


class MemoryError(SymphraExcelError):
    """当内存管理出现问题时引发此异常"""

    pass


class AsyncError(SymphraExcelError):
    """当异步操作出现问题时引发此异常"""

    pass


class ImageError(SymphraExcelError):
    """当图片处理出现问题时引发此异常"""

    pass


class WorksheetError(SymphraExcelError):
    """当工作表操作出现问题时引发此异常"""

    pass


# ==================== 异常处理装饰器 ====================


def handle_exceptions(
    *,
    error_type: type[SymphraExcelError] = SymphraExcelError,
    error_message: str = "操作失败",
    log_error: bool = True,
    reraise: bool = True,
    default_return: Any = None,
) -> Callable[[F], F]:
    """
    通用异常处理装饰器

    参数:
        error_type: 要抛出的异常类型
        error_message: 错误消息模板
        log_error: 是否记录错误日志
        reraise: 是否重新抛出异常（如果False，返回default_return）
        default_return: 当reraise=False时的默认返回值

    返回:
        装饰器函数

    示例:
        @handle_exceptions(error_type=ValidationError, error_message="验证失败")
        def validate_data(data):
            # 验证逻辑
            pass
    """

    def decorator(func: F) -> F:
        @functools.wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            try:
                return func(*args, **kwargs)
            except SymphraExcelError:
                # 已经是我们的异常，直接传递
                raise
            except Exception as e:
                # 包装其他异常
                full_message = f"{error_message}: {str(e)}"

                if log_error:
                    logger.error(
                        f"函数 {func.__name__} 发生错误: {full_message}",
                        exc_info=True,
                    )

                if reraise:
                    raise error_type(full_message, details=str(e)) from e
                else:
                    return default_return

        return wrapper  # type: ignore

    return decorator


def handle_validation_errors(
    error_message: str = "验证失败",
) -> Callable[[F], F]:
    """
    验证错误处理装饰器（handle_exceptions的便捷版本）

    参数:
        error_message: 错误消息

    返回:
        装饰器函数
    """
    return handle_exceptions(
        error_type=ValidationError,
        error_message=error_message,
    )


def handle_file_errors(
    error_message: str = "文件操作失败",
) -> Callable[[F], F]:
    """
    文件错误处理装饰器

    参数:
        error_message: 错误消息

    返回:
        装饰器函数
    """
    return handle_exceptions(
        error_type=FileFormatError,
        error_message=error_message,
    )


def handle_style_errors(
    error_message: str = "样式操作失败",
) -> Callable[[F], F]:
    """
    样式错误处理装饰器

    参数:
        error_message: 错误消息

    返回:
        装饰器函数
    """
    return handle_exceptions(
        error_type=StyleError,
        error_message=error_message,
    )


# ==================== 上下文管理器 ====================


@contextmanager
def error_context(
    operation: str,
    *,
    error_type: type[SymphraExcelError] = SymphraExcelError,
    log_error: bool = True,
    cleanup: Callable[[], None] | None = None,
) -> Generator[None, None, None]:
    """
    错误处理上下文管理器

    参数:
        operation: 操作描述
        error_type: 异常类型
        log_error: 是否记录错误
        cleanup: 清理函数（在异常发生后执行）

    异常:
        error_type: 包装后的异常

    示例:
        with error_context("读取文件", error_type=FileFormatError):
            # 文件操作
            pass
    """
    try:
        yield
    except SymphraExcelError:
        # 已经是我们的异常，直接传递
        raise
    except Exception as e:
        error_message = f"{operation}失败: {str(e)}"

        if log_error:
            logger.error(error_message, exc_info=True)

        if cleanup:
            try:
                cleanup()
            except Exception as cleanup_error:
                logger.warning(f"清理操作失败: {cleanup_error}")

        raise error_type(error_message, details=str(e)) from e


@contextmanager
def file_operation_context(
    file_path: str,
    operation: str = "文件操作",
) -> Generator[None, None, None]:
    """
    文件操作上下文管理器

    参数:
        file_path: 文件路径
        operation: 操作描述

    示例:
        with file_operation_context("data.xlsx", "读取"):
            # 文件操作
            pass
    """
    with error_context(
        f"{operation} '{file_path}'",
        error_type=FileFormatError,
    ):
        yield


@contextmanager
def resource_cleanup_context(
    *resources: Any,
    operation: str = "资源操作",
) -> Generator[None, None, None]:
    """
    资源自动清理上下文管理器

    参数:
        resources: 需要清理的资源（必须有close()方法）
        operation: 操作描述

    示例:
        file1 = open("file1.txt")
        file2 = open("file2.txt")
        with resource_cleanup_context(file1, file2, operation="处理文件"):
            # 使用资源
            pass
        # file1和file2会自动关闭，即使发生异常
    """

    def cleanup() -> None:
        for resource in resources:
            try:
                if hasattr(resource, "close"):
                    resource.close()
                elif hasattr(resource, "cleanup"):
                    resource.cleanup()
            except Exception as e:
                logger.warning(f"清理资源失败: {e}")

    try:
        with error_context(operation, cleanup=cleanup):
            yield
    finally:
        cleanup()


# ==================== 异常链工具 ====================


def get_error_chain(exception: Exception) -> list[str]:
    """
    获取异常链的所有消息

    参数:
        exception: 异常对象

    返回:
        异常消息列表（从最内层到最外层）

    示例:
        try:
            # 多层异常嵌套
            pass
        except Exception as e:
            messages = get_error_chain(e)
            # messages = ["原始错误", "包装错误1", "包装错误2"]
    """
    messages = []
    current = exception

    while current:
        messages.append(str(current))
        current = current.__cause__ or current.__context__

    return messages


def format_error_chain(exception: Exception, *, indent: str = "  ") -> str:
    """
    格式化异常链为可读字符串

    参数:
        exception: 异常对象
        indent: 缩进字符串

    返回:
        格式化的异常链字符串

    示例:
        formatted = format_error_chain(exception)
        # 输出:
        # 错误: 操作失败
        #   原因: 验证失败
        #     原因: 值超出范围
    """
    chain = get_error_chain(exception)
    if not chain:
        return str(exception)

    lines = [f"错误: {chain[0]}"]
    for msg in chain[1:]:
        lines.append(f"{indent}原因: {msg}")

    return "\n".join(lines)


# ==================== 错误日志辅助 ====================


def log_exception(
    exception: Exception,
    *,
    level: int = logging.ERROR,
    include_traceback: bool = True,
) -> None:
    """
    记录异常日志

    参数:
        exception: 异常对象
        level: 日志级别
        include_traceback: 是否包含堆栈跟踪
    """
    message = format_error_chain(exception)

    if include_traceback:
        logger.log(level, message, exc_info=True)
    else:
        logger.log(level, message)
