"""
Double-tracing prevention for framework integrations.

When a framework integration (e.g., LangChain callback handler) creates its own
LLM_CALL span with richer context (run_id, chain lineage), the underlying provider
patch (e.g., openai.py) would also fire and create a duplicate LLM span.

This module provides a ContextVar-based suppression mechanism:
- Framework integrations SET suppression before calling wrapped LLM methods
- Provider patches CHECK suppression and skip span creation if active

Usage in framework integrations:
    with suppress_provider_instrumentation():
        response = chain.invoke(input)  # LangChain callback creates LLM span
        # OpenAI provider patch sees suppression → skips span creation

Usage in provider patches (added as 1-line guard):
    if is_provider_suppressed():
        return wrapped(*args, **kwargs)
"""

from __future__ import annotations

from contextlib import asynccontextmanager, contextmanager
from contextvars import ContextVar
from typing import AsyncIterator, Iterator

# ContextVar for suppression flag — defaults to False (no suppression)
_suppress_provider_spans: ContextVar[bool] = ContextVar(
    "risicare_suppress_provider_spans", default=False
)


@contextmanager
def suppress_provider_instrumentation() -> Iterator[None]:
    """
    Context manager that suppresses provider-level span creation.

    Use this in framework integrations that create their own LLM spans
    to prevent duplicate spans from provider patches.

    Example:
        # In LangChain callback handler
        with suppress_provider_instrumentation():
            # LangChain creates its own LLM span via callback
            # OpenAI provider patch will skip span creation
            result = openai_client.chat.completions.create(...)
    """
    token = _suppress_provider_spans.set(True)
    try:
        yield
    finally:
        _suppress_provider_spans.reset(token)


@asynccontextmanager
async def async_suppress_provider_instrumentation() -> AsyncIterator[None]:
    """
    Async context manager that suppresses provider-level span creation.

    Same as suppress_provider_instrumentation() but for async contexts.
    """
    token = _suppress_provider_spans.set(True)
    try:
        yield
    finally:
        _suppress_provider_spans.reset(token)


def is_provider_suppressed() -> bool:
    """
    Check if provider-level span creation should be suppressed.

    Called by provider patches (openai.py, anthropic.py, etc.) as an
    early-exit guard. When True, the provider should call the wrapped
    function directly without creating a span.

    Returns:
        True if a framework integration is handling span creation.
    """
    suppressed = _suppress_provider_spans.get(False)
    if suppressed:
        # P2-7: Self-observability — count suppressions
        try:
            from risicare_core.observability import dedup_suppressed_total

            dedup_suppressed_total.inc()
        except Exception:
            pass
    return suppressed
