"""
OpenTelemetry TracerProvider factory for Galtea SDK.

This module provides a configured TracerProvider with appropriate span
processors for exporting traces to Galtea.
"""

import logging
from dataclasses import dataclass
from typing import Any, Optional

from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider

from galtea.infrastructure.telemetry.processors.galtea_processor import GalteaSpanProcessor

# Global tracer provider instance
_tracer_provider: Optional[TracerProvider] = None
_logger = logging.getLogger(__name__)


@dataclass
class TelemetryConfig:
    """Configuration for Galtea telemetry.

    Attributes:
            http_client: Galtea HTTP client for API requests.
            service_name: Name of the service for resource identification.
            batch_mode: If True, batch spans until flush. If False, export immediately.
    """

    http_client: Any
    service_name: str = "galtea-sdk"
    batch_mode: bool = True


def initialize_telemetry(config: TelemetryConfig) -> TracerProvider:
    """Initialize the OpenTelemetry TracerProvider with Galtea processors.

    This function sets up the global tracer provider with:
    - GalteaSpanProcessor for exporting to Galtea API

    Args:
            config: Telemetry configuration.

    Returns:
            The configured TracerProvider.
    """
    global _tracer_provider

    if _tracer_provider is not None:
        _logger.warning("Telemetry already initialized, returning existing provider")
        return _tracer_provider

    # Create resource with service info
    resource = Resource.create(
        {
            "service.name": config.service_name,
            "service.version": "1.0.0",
            "telemetry.sdk.name": "galtea",
            "telemetry.sdk.language": "python",
        }
    )

    # Create TracerProvider
    _tracer_provider = TracerProvider(resource=resource)

    # Add Galtea processor
    galtea_processor = GalteaSpanProcessor(
        http_client=config.http_client,
        batch_mode=config.batch_mode,
    )
    _tracer_provider.add_span_processor(galtea_processor)
    _logger.info("Galtea span processor registered")

    # Set as global tracer provider
    trace.set_tracer_provider(_tracer_provider)

    return _tracer_provider


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

    Args:
            name: Name for the tracer.

    Returns:
            A Tracer instance.

    Raises:
            RuntimeError: If telemetry has not been initialized.
    """
    global _tracer_provider

    if _tracer_provider is None:
        # Return a no-op tracer if not initialized
        return trace.get_tracer(name)

    return _tracer_provider.get_tracer(name)


def get_tracer_provider() -> Optional[TracerProvider]:
    """Get the global tracer provider.

    Returns:
            The TracerProvider or None if not initialized.
    """
    return _tracer_provider


def shutdown_telemetry() -> None:
    """Shutdown the telemetry system and flush pending spans."""
    global _tracer_provider

    if _tracer_provider is not None:
        _tracer_provider.shutdown()
        _tracer_provider = None
        _logger.info("Telemetry shutdown complete")


def flush_telemetry(timeout_millis: Optional[int] = None) -> bool:
    """Force flush all pending spans.

    Args:
            timeout_millis: Optional timeout in milliseconds.

    Returns:
            True if flush was successful.
    """
    global _tracer_provider

    if _tracer_provider is not None:
        return _tracer_provider.force_flush(timeout_millis)
    return True


def flush_inference(inference_result_id: str) -> None:
    """Flush spans for a specific inference result.

    Args:
            inference_result_id: The inference result ID to flush.
    """
    global _tracer_provider

    if _tracer_provider is None:
        return

    # Find and flush the Galtea processor
    for processor in _tracer_provider._active_span_processor._span_processors:
        if isinstance(processor, GalteaSpanProcessor):
            processor.flush_inference(inference_result_id)
            break
