"""
Distributed tracing configuration for TASC-Stack services.

Configures OpenTelemetry with OTLP HTTP export to Tempo, automatic
FastAPI instrumentation, and httpx context propagation.

Resilient by design: if Tempo is unreachable, spans are silently dropped
with no error spam — the service runs unaffected.

Usage:
    from common.tracing import configure_tracing

    configure_tracing(service_name="actx-server", settings=settings, app=app)
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from loguru import logger

if TYPE_CHECKING:
    from fastapi import FastAPI
    from common.config import CommonSettings


def _make_resilient_exporter(endpoint: str):
    """Wrap OTLPSpanExporter so export failures are silently dropped."""
    from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult

    inner = None
    _warned = False

    class _ResilientExporter(SpanExporter):
        def export(self, spans):
            nonlocal inner, _warned
            if inner is None:
                from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
                    OTLPSpanExporter,
                )
                inner = OTLPSpanExporter(endpoint=endpoint, timeout=5)
            try:
                return inner.export(spans)
            except Exception:
                if not _warned:
                    logger.warning(
                        f"Tempo unreachable at {endpoint}, spans will be dropped "
                        f"(this warning is logged once)"
                    )
                    _warned = True
                return SpanExportResult.FAILURE

        def shutdown(self):
            if inner is not None:
                inner.shutdown()

        def force_flush(self, timeout_millis=None):
            if inner is not None:
                try:
                    return inner.force_flush(timeout_millis)
                except Exception:
                    return False
            return True

    return _ResilientExporter()


def configure_tracing(
    service_name: str,
    settings: CommonSettings | None = None,
    app: FastAPI | None = None,
    endpoint: str | None = None,
) -> None:
    """
    Configure OpenTelemetry tracing with OTLP HTTP export.

    Args:
        service_name: Name of the service (used as resource attribute).
        settings: CommonSettings instance to extract endpoint and environment.
        app: FastAPI application to instrument. If None, only httpx
             propagation and trace context are configured.
        endpoint: OTLP HTTP endpoint. Defaults to settings.TEMPO_OTLP_ENDPOINT
                  or "http://tempo:4318".
    """
    try:
        from opentelemetry import trace
        from opentelemetry.sdk.trace import TracerProvider
        from opentelemetry.sdk.trace.export import BatchSpanProcessor
        from opentelemetry.sdk.resources import Resource
    except ImportError:
        logger.debug("OpenTelemetry SDK not installed, skipping tracing configuration")
        return

    # Resolve endpoint
    if endpoint is None:
        endpoint = getattr(settings, "TEMPO_OTLP_ENDPOINT", None) if settings else None
        endpoint = endpoint or "http://tempo:4318"

    environment = getattr(settings, "ENVIRONMENT", "unknown") if settings else "unknown"

    # Build resource attributes
    resource = Resource.create({
        "service.name": service_name,
        "deployment.environment": environment,
    })

    # Create and set tracer provider with resilient exporter
    provider = TracerProvider(resource=resource)
    exporter = _make_resilient_exporter(f"{endpoint}/v1/traces")
    provider.add_span_processor(BatchSpanProcessor(exporter))
    trace.set_tracer_provider(provider)

    # Instrument httpx for automatic W3C TraceContext propagation
    try:
        from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
        HTTPXClientInstrumentor().instrument()
    except ImportError:
        logger.debug("opentelemetry-instrumentation-httpx not installed, skipping httpx instrumentation")

    # Instrument FastAPI if app is provided
    if app is not None:
        try:
            from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
            FastAPIInstrumentor.instrument_app(app)
        except ImportError:
            logger.debug("opentelemetry-instrumentation-fastapi not installed, skipping FastAPI instrumentation")

    logger.info(f"Tracing configured for {service_name} → {endpoint}")
