from __future__ import annotations

import asyncio
import logging
from typing import Any, Coroutine

logger = logging.getLogger(__name__)

_background_tasks: set[asyncio.Task[Any]] = set()


def fire_and_forget(coro: Coroutine[Any, Any, Any]) -> asyncio.Task[Any]:
    """Schedule a coroutine as a background task without blocking the caller.

    Holds a strong reference so the task is not garbage-collected before completion.
    """
    task = asyncio.create_task(coro)
    _background_tasks.add(task)

    def _on_done(t: asyncio.Task[Any]) -> None:
        _background_tasks.discard(t)
        if t.cancelled():
            return
        if exc := t.exception():
            logger.warning("Background task failed: %s", exc)

    task.add_done_callback(_on_done)
    return task


async def drain() -> None:
    """Await all pending background tasks. Call during shutdown or test teardown."""
    while _background_tasks:
        await asyncio.gather(*_background_tasks, return_exceptions=True)
