"""装饰器工具"""

import functools
import time
from typing import Callable, Type, Tuple, Any, Optional

from ..reference import INFO


def retry(
    max_attempts: int = 3,
    delay: float = 1.0,
    exceptions: Tuple[Type[Exception], ...] = (Exception,),
    on_retry: Optional[Callable] = None
):
    """重试装饰器

    Args:
        max_attempts: 最大重试次数
        delay: 重试间隔 (秒)
        exceptions: 需要重试的异常类型
        on_retry: 重试时的回调函数

    Example:
        @retry(max_attempts=3, delay=1.0)
        def unstable_function():
            ...
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            last_exception = None

            for attempt in range(1, max_attempts + 1):
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    last_exception = e
                    if attempt < max_attempts:
                        INFO(f"第 {attempt} 次尝试失败: {e}, {delay}s 后重试...", "WARNING")
                        if on_retry:
                            on_retry(attempt, e)
                        time.sleep(delay)
                    else:
                        INFO(f"达到最大重试次数 ({max_attempts}), 放弃", "ERROR")

            raise last_exception

        return wrapper
    return decorator


def timeout(seconds: float, default: Any = None, raise_error: bool = True):
    """超时装饰器 (使用线程实现)

    Args:
        seconds: 超时时间 (秒)
        default: 超时时返回的默认值
        raise_error: 超时时是否抛出异常

    Example:
        @timeout(10.0)
        def slow_function():
            ...
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            import threading
            result = [default]
            exception = [None]

            def target():
                try:
                    result[0] = func(*args, **kwargs)
                except Exception as e:
                    exception[0] = e

            thread = threading.Thread(target=target)
            thread.daemon = True
            thread.start()
            thread.join(timeout=seconds)

            if thread.is_alive():
                if raise_error:
                    raise TimeoutError(f"函数 {func.__name__} 执行超时 ({seconds}s)")
                INFO(f"函数 {func.__name__} 执行超时 ({seconds}s)", "WARNING")
                return default

            if exception[0]:
                raise exception[0]

            return result[0]

        return wrapper
    return decorator


def catch_exception(
    exceptions: Tuple[Type[Exception], ...] = (Exception,),
    default: Any = None,
    log_error: bool = True
):
    """异常捕获装饰器

    Args:
        exceptions: 要捕获的异常类型
        default: 异常时返回的默认值
        log_error: 是否记录错误日志

    Example:
        @catch_exception(default=None)
        def risky_function():
            ...
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            try:
                return func(*args, **kwargs)
            except exceptions as e:
                if log_error:
                    INFO(f"函数 {func.__name__} 发生异常: {e}", "WARNING")
                return default

        return wrapper
    return decorator


def log_execution(log_args: bool = True, log_result: bool = True):
    """执行日志装饰器

    Args:
        log_args: 是否记录参数
        log_result: 是否记录返回值

    Example:
        @log_execution()
        def important_function(a, b):
            ...
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            func_name = func.__name__

            if log_args:
                args_repr = [repr(a) for a in args]
                kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]
                signature = ", ".join(args_repr + kwargs_repr)
                INFO(f"调用 {func_name}({signature})")
            else:
                INFO(f"调用 {func_name}()")

            start_time = time.time()
            result = func(*args, **kwargs)
            elapsed = time.time() - start_time

            if log_result:
                INFO(f"{func_name} 返回: {result!r} (耗时: {elapsed:.3f}s)")
            else:
                INFO(f"{func_name} 完成 (耗时: {elapsed:.3f}s)")

            return result

        return wrapper
    return decorator


def singleton(cls: Type) -> Type:
    """单例装饰器

    Example:
        @singleton
        class MyClass:
            ...
    """
    instances = {}

    @functools.wraps(cls)
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return get_instance


def deprecated(message: str = ""):
    """弃用警告装饰器

    Args:
        message: 弃用说明

    Example:
        @deprecated("请使用 new_function 代替")
        def old_function():
            ...
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            import warnings
            warn_msg = f"{func.__name__} 已弃用"
            if message:
                warn_msg += f": {message}"
            warnings.warn(warn_msg, DeprecationWarning, stacklevel=2)
            return func(*args, **kwargs)

        return wrapper
    return decorator
