"""OpenTelemetry tracer integration with no-op fallback."""
from __future__ import annotations

import logging
from dataclasses import dataclass, field
from typing import Any, ContextManager

logger = logging.getLogger(__name__)


@dataclass
class TelemetryConfig:
    """Telemetry configuration."""

    enabled: bool = False
    otlp_endpoint: str = ""
    service_name: str = "agentkit"
    sample_rate: float = 1.0


class NoOpSpan:
    """No-op span when telemetry is disabled."""

    def __enter__(self):
        return self

    def __exit__(self, *args):
        pass

    def set_attribute(self, key: str, value: Any) -> None:
        pass

    def add_event(self, name: str, attributes: dict[str, Any] | None = None) -> None:
        pass

    def record_exception(self, exception: Exception) -> None:
        pass

    def is_recording(self) -> bool:
        return False


class NoOpTracer:
    """No-op tracer when telemetry is disabled."""

    def start_span(self, name: str, attributes: dict[str, Any] | None = None) -> ContextManager[NoOpSpan]:
        return NoOpSpan()

    def start_as_current_span(self, name: str, attributes: dict[str, Any] | None = None) -> ContextManager[NoOpSpan]:
        return NoOpSpan()


class OTelSpan:
    """Wrapper around OpenTelemetry Span."""

    def __init__(self, span: Any):
        self._span = span

    def __enter__(self):
        self._span.__enter__()
        return self

    def __exit__(self, *args):
        self._span.__exit__(*args)

    def set_attribute(self, key: str, value: Any) -> None:
        self._span.set_attribute(key, value)

    def add_event(self, name: str, attributes: dict[str, Any] | None = None) -> None:
        self._span.add_event(name, attributes or {})

    def record_exception(self, exception: Exception) -> None:
        self._span.record_exception(exception)

    def is_recording(self) -> bool:
        return self._span.is_recording()


class OTelTracer:
    """Wrapper around OpenTelemetry Tracer."""

    def __init__(self, tracer: Any):
        self._tracer = tracer

    def start_span(self, name: str, attributes: dict[str, Any] | None = None) -> OTelSpan:
        span = self._tracer.start_span(name, attributes=attributes)
        return OTelSpan(span)

    def start_as_current_span(self, name: str, attributes: dict[str, Any] | None = None) -> OTelSpan:
        span = self._tracer.start_as_current_span(name, attributes=attributes)
        return OTelSpan(span)


# Global tracer instance
_tracer: NoOpTracer | OTelTracer = NoOpTracer()


def get_tracer() -> NoOpTracer | OTelTracer:
    """Get the global tracer instance."""
    return _tracer


def init_telemetry(config: TelemetryConfig) -> None:
    """Initialize telemetry with the given configuration."""
    global _tracer

    if not config.enabled:
        _tracer = NoOpTracer()
        logger.info("Telemetry disabled, using no-op tracer")
        return

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

        resource = Resource.create({"service.name": config.service_name})
        provider = TracerProvider(resource=resource)

        if config.otlp_endpoint:
            exporter = OTLPSpanExporter(endpoint=config.otlp_endpoint)
            provider.add_span_processor(BatchSpanProcessor(exporter))

        trace.set_tracer_provider(provider)
        _tracer = OTelTracer(trace.get_tracer(config.service_name))
        logger.info(f"Telemetry initialized with endpoint: {config.otlp_endpoint}")
    except ImportError:
        logger.warning("opentelemetry packages not installed, using no-op tracer")
        _tracer = NoOpTracer()
    except Exception as e:
        logger.warning(f"Failed to initialize telemetry: {e}, using no-op tracer")
        _tracer = NoOpTracer()
