"""Bounded thread offload helper using the application's shared executor."""

from __future__ import annotations

import asyncio
from collections.abc import Callable
from concurrent.futures import Executor
from functools import partial
from typing import Any, TypeVar


ResultT = TypeVar("ResultT")


async def run_blocking(
    function: Callable[..., ResultT],
    *args: Any,
    executor: Executor | None = None,
    **kwargs: Any,
) -> ResultT:
    """Run blocking native/SDK code without starving the event loop.

    Plugins should pass the bounded ``thread_executor`` from ComponentContext
    metadata.  Leaving it unset deliberately uses the host loop's executor
    without replacing or taking ownership of that executor.
    """

    call = partial(function, *args, **kwargs)
    return await asyncio.get_running_loop().run_in_executor(executor, call)


__all__ = ["run_blocking"]
