import math
from typing import Any


def sanitize_for_json(obj: Any) -> Any:
    """Recursively convert values that are not JSON-compliant into safe values.

    Starlette's JSONResponse uses `allow_nan=False`, so float('nan')/inf will crash.
    We convert NaN/Inf to None while preserving normal floats.
    """

    if obj is None:
        return None

    if isinstance(obj, float):
        if math.isnan(obj) or math.isinf(obj):
            return None
        return obj

    # numpy support (optional)
    try:
        import numpy as np  # type: ignore

        if isinstance(obj, (np.integer,)):
            return int(obj)
        if isinstance(obj, (np.floating,)):
            v = float(obj)
            if math.isnan(v) or math.isinf(v):
                return None
            return v
        if isinstance(obj, (np.ndarray,)):
            return sanitize_for_json(obj.tolist())
    except Exception:
        # numpy not installed or other import/runtime issues
        pass

    if isinstance(obj, dict):
        return {k: sanitize_for_json(v) for k, v in obj.items()}

    if isinstance(obj, (list, tuple, set)):
        return [sanitize_for_json(v) for v in obj]

    return obj
