"""重试逻辑处理"""

import time
from typing import Callable, TypeVar, Set
from .exceptions import OctenAPIError, OctenTimeoutError, OctenConnectionError

T = TypeVar("T")


class RetryHandler:
    """重试处理器，支持指数退避策略

    Attributes:
        max_retries: 最大重试次数
        base_delay: 基础延迟时间（秒）
        max_delay: 最大延迟时间（秒）
    """

    # 可重试的 HTTP 状态码
    RETRYABLE_STATUS_CODES: Set[int] = {
        408,  # Request Timeout
        429,  # Too Many Requests
        500,  # Internal Server Error
        502,  # Bad Gateway
        503,  # Service Unavailable
        504,  # Gateway Timeout
    }

    def __init__(
        self,
        max_retries: int = 3,
        base_delay: float = 1.0,
        max_delay: float = 60.0,
    ):
        self.max_retries = max_retries
        self.base_delay = base_delay
        self.max_delay = max_delay

    def execute(self, func: Callable[[], T]) -> T:
        """执行函数，失败时自动重试

        Args:
            func: 要执行的函数

        Returns:
            函数的返回值

        Raises:
            最后一次尝试的异常
        """
        last_exception = None

        for attempt in range(self.max_retries + 1):
            try:
                return func()
            except (OctenAPIError, OctenTimeoutError, OctenConnectionError) as e:
                last_exception = e

                # 检查是否应该重试
                if not self._should_retry(e, attempt):
                    raise

                # 如果不是最后一次尝试，等待后重试
                if attempt < self.max_retries:
                    delay = self._calculate_delay(attempt, e)
                    time.sleep(delay)

        # 所有重试都失败，抛出最后一个异常
        if last_exception:
            raise last_exception

    def _should_retry(self, error: Exception, attempt: int) -> bool:
        """判断是否应该重试

        Args:
            error: 发生的错误
            attempt: 当前尝试次数（从 0 开始）

        Returns:
            是否应该重试
        """
        # 已达最大重试次数
        if attempt >= self.max_retries:
            return False

        # 超时错误可重试
        if isinstance(error, OctenTimeoutError):
            return True

        # 连接错误可重试
        if isinstance(error, OctenConnectionError):
            return True

        # API 错误根据状态码判断
        if isinstance(error, OctenAPIError):
            if error.status_code in self.RETRYABLE_STATUS_CODES:
                return True

        return False

    def _calculate_delay(self, attempt: int, error: Exception) -> float:
        """计算延迟时间（指数退避）

        Args:
            attempt: 当前尝试次数（从 0 开始）
            error: 发生的错误

        Returns:
            延迟时间（秒）
        """
        # 如果是速率限制错误且有 retry_after 头，使用它
        if isinstance(error, OctenAPIError) and error.status_code == 429:
            if hasattr(error, "retry_after") and error.retry_after:
                return min(error.retry_after, self.max_delay)

        # 指数退避: base_delay * 2^attempt
        delay = self.base_delay * (2**attempt)

        # 限制最大延迟
        return min(delay, self.max_delay)


class AsyncRetryHandler(RetryHandler):
    """异步重试处理器"""

    async def execute_async(self, func: Callable[[], T]) -> T:
        """异步执行函数，失败时自动重试

        Args:
            func: 要执行的异步函数

        Returns:
            函数的返回值

        Raises:
            最后一次尝试的异常
        """
        import asyncio

        last_exception = None

        for attempt in range(self.max_retries + 1):
            try:
                return await func()
            except (OctenAPIError, OctenTimeoutError, OctenConnectionError) as e:
                last_exception = e

                # 检查是否应该重试
                if not self._should_retry(e, attempt):
                    raise

                # 如果不是最后一次尝试，等待后重试
                if attempt < self.max_retries:
                    delay = self._calculate_delay(attempt, e)
                    await asyncio.sleep(delay)

        # 所有重试都失败，抛出最后一个异常
        if last_exception:
            raise last_exception
