import logging
import random
from typing import List, Optional
from . import BasePlugin

logger = logging.getLogger("nebulascrape.plugins.proxy_manager")


class ProxyManagerPlugin(BasePlugin):
    name = "proxy_manager"
    priority = 30

    def __init__(
        self,
        proxies: List[str] = None,
        rotate_on_fail: bool = True,
        rotate_on_status: List[int] = None,
    ):
        self._proxies = proxies or []
        self._rotate_on_fail = rotate_on_fail
        self._rotate_on_status = rotate_on_status or [403, 429, 503]
        self._current_index = 0
        self._failure_counts: dict = {}

    def _format_proxy(self, proxy_str: str) -> dict:
        return {"http": proxy_str, "https": proxy_str}

    def _current_proxy(self) -> Optional[str]:
        if not self._proxies:
            return None
        return self._proxies[self._current_index % len(self._proxies)]

    def _rotate(self):
        if self._proxies:
            self._current_index = (self._current_index + 1) % len(self._proxies)
            logger.debug(f"[ProxyManager] Rotated to proxy: {self._current_proxy()}")

    def add_proxy(self, proxy: str):
        self._proxies.append(proxy)

    def on_pre_request(self, scraper, method, url, kwargs):
        proxy = self._current_proxy()
        if proxy and "proxies" not in kwargs:
            kwargs["proxies"] = self._format_proxy(proxy)
        return kwargs

    def on_post_request(self, scraper, response, kwargs):
        if response.status_code in self._rotate_on_status and self._rotate_on_fail:
            proxy = self._current_proxy()
            if proxy:
                self._failure_counts[proxy] = self._failure_counts.get(proxy, 0) + 1
                if self._failure_counts[proxy] >= 2:
                    logger.info(f"[ProxyManager] Proxy {proxy} failed twice — rotating")
                    self._rotate()
        elif response.status_code == 200:
            proxy = self._current_proxy()
            if proxy:
                self._failure_counts[proxy] = 0
        return response
