import threading
from typing import Any, Literal, overload

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


class _ThreadLocalSession(threading.local):
    session: requests.Session | None = None


_thread_local = _ThreadLocalSession()


def _get_session_with_retry(
    retries: int = 3,
    backoff_factor: float = 0.5,
    status_forcelist: tuple[int, ...] = (500, 502, 503, 504),
    pool_connections: int = 10,
    pool_maxsize: int = 10,
) -> requests.Session:
    session = requests.Session()
    retry_strategy = Retry(
        total=retries,
        backoff_factor=backoff_factor,
        status_forcelist=status_forcelist,
        allowed_methods=["GET"],
    )
    adapter = HTTPAdapter(
        max_retries=retry_strategy,
        pool_connections=pool_connections,
        pool_maxsize=pool_maxsize,
    )
    session.mount("http://", adapter)
    session.mount("https://", adapter)
    return session


def get_session() -> requests.Session:
    if _thread_local.session is None:
        _thread_local.session = _get_session_with_retry()
    return _thread_local.session


@overload
def make_get(  # type: ignore[explicit-any]  # pragma: no cover
    url: str,
    *,
    timeout: float = 30,
    content: Literal[True],
    **kwargs: Any,  # noqa: ANN401
) -> str | None: ...


@overload
def make_get(  # type: ignore[explicit-any]  # pragma: no cover
    url: str,
    *,
    timeout: float = 30,
    content: Literal[False] = False,
    **kwargs: Any,  # noqa: ANN401
) -> Any | None: ...  # noqa: ANN401


def make_get(  # type: ignore[explicit-any]
    url: str,
    *,
    timeout: float = 30,
    content: bool = False,
    **kwargs: Any,
) -> Any | None:
    response: Response = get_session().get(url, timeout=timeout, **kwargs)  # type: ignore[misc]

    try:
        if response.status_code != 200:
            return None

        if content:
            return response.content.decode("utf-8")

        return response.json()  # type: ignore[misc]
    except ValueError:
        return None
    finally:
        response.close()
