"""Async execution utilities.

Provides a shared thread-backed executor abstraction and helpers for
running blocking callables without stalling the FastAPI event loop.
"""

from __future__ import annotations

import asyncio
import functools
from concurrent.futures import ThreadPoolExecutor
from typing import Callable, ParamSpec, TypeVar

P = ParamSpec("P")
T = TypeVar("T")

DEFAULT_BLOCKING_EXECUTOR: ThreadPoolExecutor = ThreadPoolExecutor(
    max_workers=16,
    thread_name_prefix="bangui-blocking",
)


async def run_blocking(
    func: Callable[P, T],
    *args: P.args,
    executor: ThreadPoolExecutor | None = None,
    **kwargs: P.kwargs,
) -> T:
    """Run a blocking callable in the shared thread pool.

    Args:
        func: Blocking callable to execute.
        *args: Positional arguments for the callable.
        executor: Optional custom executor. Defaults to the shared pool.
        **kwargs: Keyword arguments for the callable.

    Returns:
        The callable return value.
    """
    loop = asyncio.get_running_loop()
    executor = DEFAULT_BLOCKING_EXECUTOR if executor is None else executor
    if kwargs:
        func = functools.partial(func, *args, **kwargs)
        return await loop.run_in_executor(executor, func)
    return await loop.run_in_executor(executor, func, *args)
