"""Async bridge utilities for preserving OTel trace context across sync→async boundaries.

When Celery tasks (sync) call asyncio.run_until_complete() to run async code,
Python's asyncio drops contextvars — including the OTel span context set by
task_prerun. This module provides helpers that copy the current context into
the async execution so that logs emitted inside async code carry the correct
trace_id and span_id.

Usage in Celery tasks:
    from varicon_observability.async_bridge import run_with_trace_context

    @celery_app.task(queue="worker_integration")
    def my_task(arg1, arg2):
        return run_with_trace_context(my_async_function(arg1, arg2))
"""

import asyncio
import contextvars
import logging

logger = logging.getLogger(__name__)


def run_with_trace_context(coro):
    """Run an async coroutine while preserving the current OTel trace context.

    ``asyncio.get_event_loop().run_until_complete()`` creates a new execution
    context, which drops ``contextvars`` values — including the OTel span set
    by ``task_prerun``.  This helper snapshots the current context with
    ``contextvars.copy_context()`` and runs the event-loop call inside that
    snapshot, so all logs emitted in async code retain the correct
    ``trace_id`` and ``span_id``.

    Args:
        coro: An awaitable / coroutine to execute.

    Returns:
        The return value of the coroutine.
    """
    ctx = contextvars.copy_context()
    loop = asyncio.get_event_loop()
    return ctx.run(loop.run_until_complete, coro)
