"""Integration tests for Mode B2: Flowlines with existing Traceloop setup."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

import flowlines

from .conftest import OTLPCaptureServer, _skip_unless_openai, make_openai_call

if TYPE_CHECKING:
    from collections.abc import Callable


@pytest.fixture(autouse=True)
def _require_openai() -> None:
    _skip_unless_openai()


traceloop_sdk = pytest.importorskip(
    "traceloop.sdk", reason="traceloop-sdk not installed"
)
Traceloop = traceloop_sdk.Traceloop  # pyright: ignore[reportUnknownMemberType]


def test_all_exporters_receive_spans(
    capture_server: Callable[[], OTLPCaptureServer],
) -> None:
    """Mode B2: Flowlines, Sentry, and Traceloop servers all receive LLM spans."""
    flowlines_server = capture_server()
    sentry_server = capture_server()
    traceloop_server = capture_server()

    # Initialize Traceloop first (creates TracerProvider + instruments OpenAI)
    Traceloop.init(  # pyright: ignore[reportUnknownMemberType]
        exporter=OTLPSpanExporter(endpoint=f"{traceloop_server.endpoint}/v1/traces"),
        disable_batch=False,
    )

    # Add a Sentry exporter to the Traceloop-managed provider
    provider = trace.get_tracer_provider()
    assert isinstance(provider, TracerProvider), "Expected an SDK TracerProvider"

    sentry_processor = BatchSpanProcessor(
        OTLPSpanExporter(endpoint=f"{sentry_server.endpoint}/v1/traces")
    )
    provider.add_span_processor(sentry_processor)

    # Initialize Flowlines in Mode B2
    flowlines.init(
        api_key="test-key",
        ingest_endpoint=flowlines_server.endpoint,
        has_traceloop=True,
    )

    try:
        make_openai_call(user_id="user-b2", session_id="convo-b2")
    finally:
        sentry_processor.shutdown()  # type: ignore[no-untyped-call]
        flowlines.shutdown()

    # All three servers should receive spans
    for name, server in [
        ("flowlines", flowlines_server),
        ("sentry", sentry_server),
        ("traceloop", traceloop_server),
    ]:
        spans = server.wait_for_spans(min_count=1)
        assert len(spans) >= 1, f"{name} server: expected ≥1 span, got {len(spans)}"

    # Verify Flowlines context attributes on the Flowlines server spans
    fl_spans = flowlines_server.get_spans()
    attr_map = {a["key"]: a["value"] for a in fl_spans[0].get("attributes", [])}
    user_id_attr = attr_map.get("flowlines.user_id", {})
    user_id_value = user_id_attr.get("string_value") or user_id_attr.get(
        "stringValue", ""
    )
    assert user_id_value == "user-b2", f"Unexpected user_id: {user_id_value}"
