"""Adaptive rate control for Azure API throttling."""

import asyncio
import time
from dataclasses import dataclass
from typing import Optional

from ..utils.logging import get_logger

LOGGER = get_logger()


@dataclass
class RateLimitConfig:
    """Configuration for adaptive rate limiting."""

    initial_rps: float = 10.0  # Requests per second
    min_rps: float = 1.0
    max_rps: float = 50.0
    increase_factor: float = 1.2
    decrease_factor: float = 0.5
    backoff_base: float = 2.0
    max_retries: int = 5


class AdaptiveRateController:
    """Dynamically adjust request rate based on API responses."""

    def __init__(self, config: Optional[RateLimitConfig] = None):
        self.config = config or RateLimitConfig()
        self.current_rps = self.config.initial_rps
        self.last_request_time = 0.0
        self.consecutive_successes = 0
        self.consecutive_failures = 0
        self._lock = asyncio.Lock()

    async def acquire(self) -> None:
        """Wait until next request is allowed."""
        async with self._lock:
            now = time.time()
            min_interval = 1.0 / self.current_rps
            elapsed = now - self.last_request_time

            if elapsed < min_interval:
                await asyncio.sleep(min_interval - elapsed)

            self.last_request_time = time.time()

    async def record_success(self) -> None:
        """Record successful request and potentially increase rate."""
        async with self._lock:
            self.consecutive_successes += 1
            self.consecutive_failures = 0

            # Gradually increase rate after sustained success
            if self.consecutive_successes >= 10:
                old_rps = self.current_rps
                self.current_rps = min(
                    self.config.max_rps,
                    self.current_rps * self.config.increase_factor,
                )
                self.consecutive_successes = 0
                LOGGER.debug(
                    "Increased request rate",
                    extra={
                        "context": {
                            "old_rps": old_rps,
                            "new_rps": self.current_rps,
                        }
                    },
                )

    async def record_throttle(self, retry_after: Optional[int] = None) -> None:
        """Record throttling event and decrease rate."""
        async with self._lock:
            self.consecutive_failures += 1
            self.consecutive_successes = 0

            # Aggressively decrease rate
            old_rps = self.current_rps
            self.current_rps = max(
                self.config.min_rps, self.current_rps * self.config.decrease_factor
            )

            LOGGER.warning(
                "Request throttled, decreased rate",
                extra={
                    "context": {
                        "old_rps": old_rps,
                        "new_rps": self.current_rps,
                        "retry_after": retry_after,
                    }
                },
            )

            # Honor Retry-After header if provided
            if retry_after:
                await asyncio.sleep(retry_after)

    def get_backoff_delay(self, attempt: int) -> float:
        """Calculate exponential backoff delay.

        Args:
            attempt: Retry attempt number (0-indexed)

        Returns:
            Delay in seconds, capped at 60 seconds
        """
        return min(60.0, self.config.backoff_base**attempt)

    async def reset(self) -> None:
        """Reset controller to initial state."""
        async with self._lock:
            self.current_rps = self.config.initial_rps
            self.last_request_time = 0.0
            self.consecutive_successes = 0
            self.consecutive_failures = 0

    def get_current_rps(self) -> float:
        """Get current requests per second rate.

        Returns:
            Current RPS setting
        """
        return self.current_rps
