"""Internal tracer singleton and OTel provider configuration."""

import logging

from opentelemetry import trace as trace_api
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
    OTLPSpanExporter as OTLPSpanExporterGRPC,
)
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
    OTLPSpanExporter as OTLPSpanExporterHTTP,
)
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
    BatchSpanProcessor,
    ConsoleSpanExporter,
    SimpleSpanProcessor,
    SpanExporter,
    SpanProcessor,
)

logger = logging.getLogger("plyra_trace")

_tracer_provider: TracerProvider | None = None


def configure(
    project: str,
    endpoint: str | None = None,
    protocol: str = "http/protobuf",
    environment: str = "development",
    headers: dict[str, str] | None = None,
    span_processors: list[SpanProcessor] | None = None,
    batch: bool = True,
    filter_spans: list[str] | None = None,
) -> trace_api.Tracer:
    """
    Configure the OTel TracerProvider singleton.

    Args:
        project: Project name, sets service.name resource attribute
        endpoint: OTLP endpoint URL. If None, uses ConsoleSpanExporter
        protocol: "http/protobuf" or "grpc"
        environment: Deployment environment, sets deployment.environment
            resource attribute
        headers: Optional auth headers for managed backends
        span_processors: Additional SpanProcessors to register
            (e.g., compat processors)
        batch: Use BatchSpanProcessor (True) or SimpleSpanProcessor (False)

    Returns:
        Configured Tracer instance
    """
    global _tracer_provider

    # Create resource with project and environment
    resource = Resource.create(
        {
            "service.name": project,
            "deployment.environment": environment,
            "telemetry.sdk.name": "plyra-trace",
            "telemetry.sdk.version": "1.0.0",
        }
    )

    # Create new tracer provider
    _tracer_provider = TracerProvider(resource=resource)

    # Choose exporter
    exporter: SpanExporter
    if endpoint is None:
        logger.info("No endpoint configured, using ConsoleSpanExporter (dev mode)")
        exporter = ConsoleSpanExporter()
    else:
        if protocol == "grpc":
            logger.info(f"Configuring OTLP gRPC exporter: {endpoint}")
            exporter = OTLPSpanExporterGRPC(
                endpoint=endpoint,
                headers=headers or {},
            )
        else:  # http/protobuf
            logger.info(f"Configuring OTLP HTTP exporter: {endpoint}")
            exporter = OTLPSpanExporterHTTP(
                endpoint=f"{endpoint}/v1/traces" if not endpoint.endswith("/v1/traces") else endpoint,
                headers=headers or {},
            )

    # Create span processor (optionally wrapped with noise filter)
    processor_class = BatchSpanProcessor if batch else SimpleSpanProcessor
    main_processor: SpanProcessor = processor_class(exporter)
    if filter_spans:
        from plyra_trace.processor import NoiseFilterProcessor

        main_processor = NoiseFilterProcessor(main_processor, filter_spans)
    _tracer_provider.add_span_processor(main_processor)

    # Add context span processor (for session/user/metadata/tags)
    from plyra_trace.context import ContextSpanProcessor

    _tracer_provider.add_span_processor(ContextSpanProcessor())

    # Add any additional processors (e.g., compat processors)
    if span_processors:
        for processor in span_processors:
            _tracer_provider.add_span_processor(processor)

    # Set as global provider
    trace_api.set_tracer_provider(_tracer_provider)

    logger.info(f"plyra-trace initialized: project={project}, environment={environment}")

    return _tracer_provider.get_tracer("plyra-trace")


def get_tracer(name: str = "plyra-trace") -> trace_api.Tracer:
    """
    Get a tracer from the configured provider.

    Args:
        name: Tracer name (default: "plyra-trace")

    Returns:
        Tracer instance

    Raises:
        RuntimeError: If configure() has not been called
    """
    if _tracer_provider is None:
        raise RuntimeError("plyra-trace not initialized. Call plyra_trace.init() first.")
    return _tracer_provider.get_tracer(name)


def get_provider() -> TracerProvider | None:
    """Get the current tracer provider (for internal use)."""
    return _tracer_provider


def shutdown() -> None:
    """Shutdown the tracer provider and flush pending spans."""
    global _tracer_provider
    if _tracer_provider is not None:
        logger.info("Shutting down plyra-trace")
        _tracer_provider.shutdown()
        _tracer_provider = None
