"""
URL safety utilities for validating URL schemes before opening.

Addresses Bandit B310: Audit url open for permitted schemes.
"""

import urllib.request
from urllib.parse import urlparse

# Only allow HTTP(S) schemes to prevent file:// and other protocol attacks.
ALLOWED_SCHEMES = frozenset({"http", "https"})


def safe_urlopen(url_or_request, *, timeout=None, allowed_schemes=None):
    """
    Open a URL after validating the scheme is in the allowlist.

    Accepts either a string URL or a urllib.request.Request object.

    Args:
        url_or_request: URL string or urllib.request.Request to open.
        timeout: Optional timeout in seconds.
        allowed_schemes: Optional frozenset of allowed schemes.
                         Defaults to {"http", "https"}.

    Returns:
        The response object from urllib.request.urlopen.

    Raises:
        ValueError: If the URL scheme is not in the allowlist.
    """
    schemes = allowed_schemes or ALLOWED_SCHEMES

    if isinstance(url_or_request, urllib.request.Request):
        url = url_or_request.full_url
    else:
        url = url_or_request

    parsed = urlparse(url)
    if parsed.scheme not in schemes:
        raise ValueError(
            f"URL scheme '{parsed.scheme}' is not allowed. "
            f"Permitted schemes: {sorted(schemes)}"
        )

    kwargs = {}
    if timeout is not None:
        kwargs["timeout"] = timeout

    return urllib.request.urlopen(url_or_request, **kwargs)  # nosec B310
