"""
Eagerly preload the CUDA 12 runtime shared libraries bundled by the
`nvidia-*-cu12` wheels so that `onnxruntime-gpu`'s `CUDAExecutionProvider`
can resolve them via `dlopen`.

Why this exists
---------------
`onnxruntime-gpu` (>=1.26.0) is built against CUDA 12. On hosts running
CUDA 13 (driver 580+) the system loader cannot find `libcublasLt.so.12`,
`libcudnn.so.9`, etc. — and `CUDAExecutionProvider` silently falls back
to CPU. The `nvidia-*-cu12` pip wheels install the libraries under
`<site-packages>/nvidia/<pkg>/lib/`, but the dynamic linker does not
search those paths by default and the wheels do not register them.

`ctypes.CDLL(path, RTLD_GLOBAL)` at import time makes the libraries'
symbols available to subsequent `dlopen` calls from onnxruntime, without
requiring callers to export `LD_LIBRARY_PATH`.

This is best-effort: a CPU-only environment without the `nvidia-*-cu12`
wheels installed will skip the preload silently. RapidOCR will then run
on CPU as before — extraction still works, just slower.
"""

from __future__ import annotations

import ctypes
import sys
from pathlib import Path

_CUDA_LIB_SONAMES = (
    "libcublasLt.so.12",
    "libcublas.so.12",
    "libcurand.so.10",
    "libcufft.so.11",
    "libcudart.so.12",
    "libcudnn.so.9",
)


def preload_cuda_runtime_libs() -> list[str]:
    """Preload CUDA 12 sonames from the `nvidia-*-cu12` pip wheels.

    Returns the list of soname strings that were successfully loaded.
    Silent on missing wheels (CPU-only environments) and on individual
    `OSError`s during `dlopen`.
    """
    site_packages = (
        Path(sys.prefix)
        / "lib"
        / f"python{sys.version_info.major}.{sys.version_info.minor}"
        / "site-packages"
    )
    nvidia_root = site_packages / "nvidia"
    if not nvidia_root.is_dir():
        return []

    loaded: list[str] = []
    for soname in _CUDA_LIB_SONAMES:
        for path in nvidia_root.rglob(soname):
            try:
                ctypes.CDLL(str(path), mode=ctypes.RTLD_GLOBAL)
                loaded.append(soname)
                break
            except OSError:
                continue
    return loaded
