"""Rate limiting and retry logic for Google APIs."""

from __future__ import annotations

import functools
import logging
import random
import threading
import time
from collections import defaultdict

from googleapiclient.errors import HttpError

logger = logging.getLogger("seo_optimizer")


class RateLimiter:
    """Per-site QPM rate limiter. Thread-safe."""

    def __init__(self, max_qpm: int = 1200):
        self.max_qpm = max_qpm
        self._lock = threading.Lock()
        self._timestamps: dict[str, list[float]] = defaultdict(list)

    def acquire(self, site: str = "default") -> None:
        """Block until a request slot is available for the given site."""
        while True:
            with self._lock:
                now = time.monotonic()
                window_start = now - 60.0

                # Remove timestamps outside the 1-minute window
                self._timestamps[site] = [
                    t for t in self._timestamps[site] if t > window_start
                ]

                if len(self._timestamps[site]) < self.max_qpm:
                    self._timestamps[site].append(now)
                    return

                # Calculate wait time until oldest request exits the window
                oldest = self._timestamps[site][0]
                wait_time = oldest - window_start

            time.sleep(max(wait_time, 0.05))


class QuotaTracker:
    """Daily quota tracker for URL Inspection API (2,000/day)."""

    def __init__(self, daily_limit: int = 2000):
        self.daily_limit = daily_limit
        self._lock = threading.Lock()
        self._count = 0

    @property
    def remaining(self) -> int:
        with self._lock:
            return max(0, self.daily_limit - self._count)

    def acquire(self) -> bool:
        """Try to acquire a quota slot. Returns False if limit reached."""
        with self._lock:
            if self._count >= self.daily_limit:
                return False
            self._count += 1
            return True

    def reset(self) -> None:
        with self._lock:
            self._count = 0


def retry_on_api_error(max_retries: int = 5, base_delay: float = 1.0):
    """Decorator: exponential backoff retry on 429/500/503 HttpError."""

    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries + 1):
                try:
                    return func(*args, **kwargs)
                except HttpError as e:
                    status = e.resp.status if e.resp else 0
                    if status in (429, 500, 503) and attempt < max_retries:
                        delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
                        logger.warning(
                            "API error %d on attempt %d/%d for %s, retrying in %.1fs",
                            status, attempt + 1, max_retries, func.__name__, delay,
                        )
                        time.sleep(delay)
                    else:
                        raise

        return wrapper

    return decorator
