"""
OpenTelemetry integration for releaseops telemetry.

Injects bundle metadata into OpenTelemetry spans as attributes,
enabling filtering and correlation in observability backends.
"""

from __future__ import annotations

import logging
from contextlib import contextmanager
from typing import TYPE_CHECKING, Generator

from opentelemetry import trace

from llmhq_releaseops.telemetry.context import _bundle_metadata
from llmhq_releaseops.telemetry.models import TelemetryContext

if TYPE_CHECKING:
    from opentelemetry.trace import Span

logger = logging.getLogger(__name__)


class OpenTelemetryIntegration:
    """
    Injects releaseops metadata into OpenTelemetry spans.

    All metadata is added as span attributes with 'releaseops.' prefix,
    making it available for filtering in Jaeger, Zipkin, Datadog, etc.
    """

    def inject_current_span(self, metadata: TelemetryContext) -> None:
        """
        Inject metadata into the current active span.

        No-op if no span is active or span is not recording.
        """
        span = trace.get_current_span()
        self.inject_span(span, metadata)

    def inject_span(self, span: Span, metadata: TelemetryContext) -> None:
        """
        Inject metadata into a specific span.

        Args:
            span: OpenTelemetry span to inject into.
            metadata: Bundle metadata to inject.
        """
        if not span.is_recording():
            logger.debug("Span is not recording, skipping metadata injection")
            return

        flat = metadata.to_flat_dict()
        for key, value in flat.items():
            span.set_attribute(key, value)

        logger.debug(
            f"Injected {len(flat)} attributes into span "
            f"for {metadata.bundle_id}@{metadata.environment}"
        )


@contextmanager
def inject_context(
    metadata: TelemetryContext,
) -> Generator[TelemetryContext, None, None]:
    """
    Context manager that sets metadata in context and injects into current span.

    On entry: sets context + injects span attributes.
    On exit: restores previous context (supports nesting).

    Usage:
        with inject_context(metadata):
            agent.run()  # All spans inside get metadata
    """
    token = _bundle_metadata.set(metadata)
    try:
        integration = OpenTelemetryIntegration()
        integration.inject_current_span(metadata)
        yield metadata
    finally:
        _bundle_metadata.reset(token)
