"""HTTP session factory.

Two deliberate choices:

* **Library-level retries are off.** `urllib3` retries below the layer that knows
  what a request means, so a retried POST can double-deploy a bot. Retry policy
  lives in `AuthManager.make_request`, which can tell a safe retry from an
  unsafe one.
* **Credentials are stripped on cross-origin redirects.** `requests` drops
  `Authorization` on a host change but keeps manually set headers, so an SSO
  redirect to an identity provider would carry `X-Authorization` off-site.
"""

from urllib.parse import urlparse

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

SENSITIVE_HEADERS = ("X-Authorization", "Authorization", "Cookie")
CONNECTION_POOL_SIZE = 10


class SafeRedirectSession(requests.Session):
    """A session that removes credentials when a redirect leaves the origin."""

    def __init__(self, origin: str) -> None:
        super().__init__()
        self._origin = _origin_of(origin)

    def rebuild_auth(self, prepared_request, response) -> None:
        super().rebuild_auth(prepared_request, response)
        if _origin_of(prepared_request.url or "") == self._origin:
            return
        for header in SENSITIVE_HEADERS:
            prepared_request.headers.pop(header, None)


def build_session(control_room_url: str, *, verify: object = True) -> requests.Session:
    """Build the shared session used for every Control Room call."""
    session = SafeRedirectSession(control_room_url)
    session.verify = verify  # type: ignore[assignment]
    adapter = HTTPAdapter(
        pool_connections=CONNECTION_POOL_SIZE,
        pool_maxsize=CONNECTION_POOL_SIZE,
        max_retries=Retry(total=0, connect=0, read=0, redirect=5, status=0),
    )
    session.mount("https://", adapter)
    session.mount("http://", adapter)
    return session


def _origin_of(url: str) -> tuple[str, str, int | None] | None:
    parsed = urlparse(url)
    if not parsed.scheme or not parsed.hostname:
        return None
    return (parsed.scheme, parsed.hostname.lower(), parsed.port)
