"""OpenTelemetry tracing integration — noop when OTEL not configured."""

from __future__ import annotations

import functools
import logging
import os
from typing import Any, Callable

logger = logging.getLogger(__name__)

_tracer = None


def setup_tracing(service_name: str = "loom", enabled: bool = True) -> None:
    """Configure OpenTelemetry tracing. Noop if OTEL SDK not installed or not enabled."""
    global _tracer
    if not enabled:
        return

    endpoint = os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT")
    if not endpoint:
        logger.debug("OTEL_EXPORTER_OTLP_ENDPOINT not set, tracing disabled")
        return

    try:
        from opentelemetry import trace
        from opentelemetry.sdk.trace import TracerProvider
        from opentelemetry.sdk.trace.export import BatchSpanProcessor
        from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

        provider = TracerProvider()
        exporter = OTLPSpanExporter(endpoint=endpoint)
        provider.add_span_processor(BatchSpanProcessor(exporter))
        trace.set_tracer_provider(provider)
        _tracer = trace.get_tracer(service_name)
        logger.info("OpenTelemetry tracing configured (endpoint=%s)", endpoint)
    except ImportError:
        logger.debug("OpenTelemetry SDK not installed, tracing disabled")


def trace_tool(name: str) -> Callable:
    """Decorator for MCP tools — creates spans with tool name and attributes."""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        async def wrapper(*args: Any, **kwargs: Any) -> Any:
            if _tracer is None:
                return await func(*args, **kwargs)

            with _tracer.start_as_current_span(f"tool.{name}") as span:
                span.set_attribute("tool.name", name)
                if "task_id" in kwargs:
                    span.set_attribute("task.id", kwargs["task_id"])
                try:
                    result = await func(*args, **kwargs)
                    span.set_attribute("tool.success", True)
                    return result
                except Exception as e:
                    span.set_attribute("tool.success", False)
                    span.set_attribute("tool.error", str(e))
                    raise
        return wrapper
    return decorator


def trace_store(name: str) -> Callable:
    """Decorator for store functions — creates spans for DB operations."""
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        async def wrapper(*args: Any, **kwargs: Any) -> Any:
            if _tracer is None:
                return await func(*args, **kwargs)

            with _tracer.start_as_current_span(f"store.{name}") as span:
                span.set_attribute("db.operation", name)
                return await func(*args, **kwargs)
        return wrapper
    return decorator
