"""
OpenTelemetry tracing configuration for Lattice MCP server.

Provides distributed observability via environment variable:
- LATTICE_TRACING_ENABLED=true to enable tracing
- Console exporter for MVP (can upgrade to OTLP later)

Usage:
    from lattice.shell.telemetry import configure_tracing, get_tracer

    # At startup
    configure_tracing()

    # In handler
    tracer = get_tracer(__name__)
    with tracer.start_as_current_span("tool.search") as span:
        span.set_attribute("query", query)
        ...
"""

from __future__ import annotations

import logging
import os
from typing import TYPE_CHECKING

from returns.result import Failure, Result, Success

if TYPE_CHECKING:
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.trace import Tracer

logger = logging.getLogger(__name__)

# Module-level state for configured tracer
_tracer_provider: TracerProvider | None = None
_tracer: Tracer | None = None


def configure_tracing() -> Result[Tracer, str]:
    """Configure OpenTelemetry tracing if enabled.

    Checks LATTICE_TRACING_ENABLED environment variable.
    Uses ConsoleSpanExporter for MVP observability.

    Returns:
        Success with Tracer if enabled and configured.
        Failure with message if disabled or configuration failed.
    """
    global _tracer_provider, _tracer

    enabled = os.environ.get("LATTICE_TRACING_ENABLED", "").lower() in (
        "true",
        "1",
        "yes",
    )

    if not enabled:
        logger.debug("OpenTelemetry tracing disabled (LATTICE_TRACING_ENABLED not set)")
        return Failure("Tracing disabled: LATTICE_TRACING_ENABLED not set to true")

    try:
        from opentelemetry.sdk.trace import TracerProvider
        from opentelemetry.sdk.trace.export import (
            BatchSpanProcessor,
            ConsoleSpanExporter,
        )
        from opentelemetry.trace import set_tracer_provider

        # Create provider with console exporter
        _tracer_provider = TracerProvider()
        exporter = ConsoleSpanExporter()
        processor = BatchSpanProcessor(exporter)
        _tracer_provider.add_span_processor(processor)

        # Set as global tracer provider
        set_tracer_provider(_tracer_provider)

        # Create and cache tracer
        _tracer = _tracer_provider.get_tracer("lattice.mcp")

        logger.info("OpenTelemetry tracing enabled (console exporter)")
        return Success(_tracer)

    except ImportError as e:
        logger.warning(f"OpenTelemetry not installed: {e}")
        return Failure(f"OpenTelemetry not installed: {e}")
    except Exception as e:
        logger.exception(f"Failed to configure OpenTelemetry: {e}")
        return Failure(f"Failed to configure tracing: {e}")


# @invar:allow shell_result: Returns Tracer directly for ergonomic use; no-op fallback handles errors
# @invar:allow shell_pure_logic: Module-level state access, no I/O operations
def get_tracer(name: str) -> Tracer:
    """Get a tracer instance.

    If tracing is not configured, returns a no-op tracer.

    Args:
        name: Name for the tracer (typically __name__).

    Returns:
        A Tracer instance (real or no-op).
    """
    if _tracer is not None:
        return _tracer_provider.get_tracer(name)  # type: ignore[union-attr]

    # Return no-op tracer if not configured
    from opentelemetry.trace import NoOpTracer, get_tracer_provider

    provider = get_tracer_provider()
    if provider is None:
        return NoOpTracer()

    return provider.get_tracer(name)


# @invar:allow shell_result: Boolean status check, no error case
# @invar:allow shell_pure_logic: Simple flag check, no I/O operations
def is_tracing_enabled() -> bool:
    """Check if tracing is currently enabled.

    Returns:
        True if tracing is configured and active.
    """
    return _tracer_provider is not None
