"""Rate limiting filter to prevent log flooding."""

import time
from collections import defaultdict, deque

from ..core.backend import LogRecord


class RateLimitFilter:
    """Filter logs to prevent flooding with rate limiting."""

    def __init__(
        self,
        max_logs_per_second: float = 10.0,
        max_logs_per_minute: int = 600,
        burst_size: int = 20,
        cooldown_period: float = 60.0
    ) -> None:
        """Initialize rate limit filter.
        
        Args:
            max_logs_per_second: Maximum logs allowed per second
            max_logs_per_minute: Maximum logs allowed per minute
            burst_size: Number of logs allowed in a burst
            cooldown_period: Period to wait after rate limit is exceeded
        """
        self.max_logs_per_second = max_logs_per_second
        self.max_logs_per_minute = max_logs_per_minute
        self.burst_size = burst_size
        self.cooldown_period = cooldown_period

        # Tracking state per logger
        self._logger_state: dict[str, tuple[deque, deque, float]] = defaultdict(
            lambda: (deque(), deque(), 0.0)
        )
        self._bucket_tokens: dict[str, float] = defaultdict(lambda: burst_size)
        self._last_refill: dict[str, float] = defaultdict(time.time)

    def should_log(self, record: LogRecord) -> bool:
        """Check if record should be logged based on rate limits.
        
        Args:
            record: The log record to check
            
        Returns:
            True if record should be logged, False otherwise
        """
        current_time = time.time()
        logger_name = record.logger_name

        # Get state for this logger
        second_logs, minute_logs, last_rate_limit = self._logger_state[logger_name]

        # Check if we're still in cooldown period
        if last_rate_limit > 0 and current_time - last_rate_limit < self.cooldown_period:
            return False

        # Clean up old entries
        self._cleanup_old_entries(second_logs, current_time, 1.0)
        self._cleanup_old_entries(minute_logs, current_time, 60.0)

        # Check per-second rate limit
        if len(second_logs) >= self.max_logs_per_second:
            self._logger_state[logger_name] = (second_logs, minute_logs, current_time)
            return False

        # Check per-minute rate limit
        if len(minute_logs) >= self.max_logs_per_minute:
            self._logger_state[logger_name] = (second_logs, minute_logs, current_time)
            return False

        # Check token bucket for burst control
        if not self._consume_token(logger_name, current_time):
            self._logger_state[logger_name] = (second_logs, minute_logs, current_time)
            return False

        # Record this log
        second_logs.append(current_time)
        minute_logs.append(current_time)
        self._logger_state[logger_name] = (second_logs, minute_logs, 0.0)  # Reset rate limit time

        return True

    def _cleanup_old_entries(self, log_times: deque, current_time: float, window: float) -> None:
        """Remove log entries older than the time window.
        
        Args:
            log_times: Deque of log timestamps
            current_time: Current timestamp
            window: Time window in seconds
        """
        while log_times and current_time - log_times[0] > window:
            log_times.popleft()

    def _consume_token(self, logger_name: str, current_time: float) -> bool:
        """Consume a token from the token bucket.
        
        Args:
            logger_name: Name of the logger
            current_time: Current timestamp
            
        Returns:
            True if token was consumed, False if no tokens available
        """
        # Refill tokens based on time passed
        time_passed = current_time - self._last_refill[logger_name]
        tokens_to_add = time_passed * self.max_logs_per_second

        self._bucket_tokens[logger_name] = min(
            self.burst_size,
            self._bucket_tokens[logger_name] + tokens_to_add
        )
        self._last_refill[logger_name] = current_time

        # Try to consume a token
        if self._bucket_tokens[logger_name] >= 1.0:
            self._bucket_tokens[logger_name] -= 1.0
            return True

        return False

    def reset_logger_limits(self, logger_name: str) -> None:
        """Reset rate limits for a specific logger.
        
        Args:
            logger_name: Name of the logger to reset
        """
        if logger_name in self._logger_state:
            del self._logger_state[logger_name]
        if logger_name in self._bucket_tokens:
            self._bucket_tokens[logger_name] = self.burst_size
        if logger_name in self._last_refill:
            self._last_refill[logger_name] = time.time()

    def get_logger_stats(self, logger_name: str) -> dict[str, float]:
        """Get rate limiting statistics for a logger.
        
        Args:
            logger_name: Name of the logger
            
        Returns:
            Dictionary with rate limiting statistics
        """
        if logger_name not in self._logger_state:
            return {
                "logs_last_second": 0,
                "logs_last_minute": 0,
                "tokens_available": self.burst_size,
                "last_rate_limit": 0.0
            }

        current_time = time.time()
        second_logs, minute_logs, last_rate_limit = self._logger_state[logger_name]

        # Clean up old entries for accurate count
        self._cleanup_old_entries(second_logs, current_time, 1.0)
        self._cleanup_old_entries(minute_logs, current_time, 60.0)

        return {
            "logs_last_second": len(second_logs),
            "logs_last_minute": len(minute_logs),
            "tokens_available": self._bucket_tokens.get(logger_name, self.burst_size),
            "last_rate_limit": last_rate_limit
        }
