from typing import Any, Sequence

# Log imports - handle OTel SDK version differences
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, LogExporter, LogExportResult
from opentelemetry.sdk.trace import ReadableSpan
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExporter, SpanExportResult

# Handle OTel SDK version differences (1.39 removed LogData)
try:
    from opentelemetry.sdk._logs import ReadableLogRecord

    OTEL_139_PLUS = True
except ImportError:
    from opentelemetry.sdk._logs import LogData

    OTEL_139_PLUS = False


class BatchExporterAdapter(SpanExporter):
    """
    Adapts BatchSpanProcessor to the SpanExporter interface.

    This allows Clarvynn to use OTel's standard BatchSpanProcessor
    as the "exporter" for its pipeline, ensuring that spans are
    exported asynchronously in batches, even after passing through
    Clarvynn's synchronous tail-sampling logic.
    """

    def __init__(self, exporter: SpanExporter):
        self.processor = BatchSpanProcessor(exporter)

    def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
        """
        Queue spans for export via BatchSpanProcessor.
        """
        for span in spans:
            self.processor.on_end(span)
        return SpanExportResult.SUCCESS

    def shutdown(self):
        self.processor.shutdown()

    def force_flush(self, timeout_millis: int = 30000) -> bool:
        return self.processor.force_flush(timeout_millis)


class BatchLogExporterAdapter(LogExporter):
    """
    Adapts BatchLogRecordProcessor to the LogExporter interface.

    Ensures logs are exported asynchronously in batches.
    """

    def __init__(self, exporter: LogExporter):
        self.processor = BatchLogRecordProcessor(exporter)

    def export(self, batch: Sequence[Any]) -> LogExportResult:
        """
        Queue logs for export via BatchLogRecordProcessor.

        Handles both old (emit) and new (on_emit) method names for SDK compatibility.
        """
        for log_data in batch:
            # Try on_emit (newer SDKs), fall back to emit (older SDKs)
            if hasattr(self.processor, "on_emit"):
                self.processor.on_emit(log_data)
            else:
                self.processor.emit(log_data)
        return LogExportResult.SUCCESS

    def shutdown(self):
        self.processor.shutdown()

    def force_flush(self, timeout_millis: int = 30000) -> bool:
        return self.processor.force_flush(timeout_millis)
