"""Proxied urllib opener — routes ALL urllib requests through detected proxy.

Without this, urllib.request.urlopen() bypasses the proxy system entirely,
and CSCA exam software blocks the direct connections.

Usage:
    from src.utils.proxied_urllib import proxied_urlopen

    # Drop-in replacement for urllib.request.urlopen:
    with proxied_urlopen(req, timeout=15) as resp:
        data = resp.read()
"""

from __future__ import annotations

import logging
import threading
import urllib.request

log = logging.getLogger(__name__)

_opener: urllib.request.OpenerDirector | None = None
_opener_lock = threading.Lock()


def _build_opener() -> urllib.request.OpenerDirector:
    """Build a urllib opener with proxy support from our detection system."""
    proxy_url = ""
    try:
        from .gfw_detect import is_behind_gfw_fast
        if is_behind_gfw_fast():
            from .proxy_tunnel import get_proxy_config
            cfg = get_proxy_config()
            if cfg and cfg.is_valid:
                # urllib ProxyHandler only supports http/https schemes
                if cfg.scheme in ("http", "https"):
                    proxy_url = cfg.url
                elif cfg.scheme.startswith("socks"):
                    # For SOCKS proxies, check if our built-in SOCKS5→HTTP
                    # bridge is running on localhost:11081
                    import socket as _socket
                    try:
                        s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
                        s.settimeout(0.3)
                        s.connect(("127.0.0.1", 11081))
                        s.close()
                        proxy_url = "http://127.0.0.1:11081"
                    except (OSError, _socket.timeout):
                        # Fall back to SOCKS proxy via env var (Python 3.x
                        # urllib doesn't support SOCKS natively, but the
                        # connection may still work via the detected proxy
                        # if env vars are set)
                        pass
    except Exception as exc:
        log.debug("[proxied_urllib] Proxy detection failed: %s", exc)

    if not proxy_url:
        # Also check environment variables directly
        import os
        for var in ("https_proxy", "HTTPS_PROXY", "http_proxy", "HTTP_PROXY"):
            val = os.environ.get(var, "").strip()
            if val and val.startswith("http"):
                proxy_url = val
                break

    if proxy_url:
        log.debug("[proxied_urllib] Using proxy: %s", proxy_url)
        handler = urllib.request.ProxyHandler({
            "http": proxy_url,
            "https": proxy_url,
        })
        return urllib.request.build_opener(handler)

    # No proxy found — return default opener (respects env vars if set later)
    return urllib.request.build_opener()


def get_opener() -> urllib.request.OpenerDirector:
    """Return a cached proxied urllib opener (thread-safe)."""
    global _opener
    with _opener_lock:
        if _opener is None:
            _opener = _build_opener()
        return _opener


def reset_opener() -> None:
    """Force re-detection of proxy on next call (e.g. after proxy config changes)."""
    global _opener
    with _opener_lock:
        _opener = None


def proxied_urlopen(req, *, timeout=15, **kwargs):
    """Drop-in replacement for urllib.request.urlopen that routes through proxy.

    Args:
        req: urllib.request.Request object or URL string.
        timeout: Connection timeout in seconds.
        **kwargs: Extra args passed to opener.open().

    Returns:
        HTTP response object (same as urlopen).
    """
    opener = get_opener()
    return opener.open(req, timeout=timeout, **kwargs)
