"""Tests for BeaconClient."""

import logging
import os
from unittest.mock import MagicMock, patch

import pytest

from lumenova_beacon import BeaconClient
from lumenova_beacon.core.transport import HTTPTransport, FileTransport
from lumenova_beacon.tracing.trace import TraceContext
from lumenova_beacon.types import SpanKind, SpanType
from lumenova_beacon.exceptions import ConfigurationError


class TestBeaconClientInitialization:
    """Test BeaconClient initialization."""

    def test_init_with_endpoint(self):
        """Test initialization with HTTP endpoint."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            api_key="test-key",
            auto_instrument_opentelemetry=False,
        )

        assert client.config.endpoint == "https://api.test.com"
        assert client.config.api_key == "test-key"
        assert isinstance(client.transport, HTTPTransport)
        assert client.transport.endpoint == "https://api.test.com"

    def test_init_with_file_directory(self, temp_span_directory):
        """Test initialization with file directory."""
        client = BeaconClient(
            file_directory=str(temp_span_directory),
            auto_instrument_opentelemetry=False,
        )

        assert client.config.file_directory == str(temp_span_directory)
        assert isinstance(client.transport, FileTransport)
        assert client.transport.directory == temp_span_directory

    def test_init_file_only_mode(self, temp_span_directory):
        """Test that file-only mode sets up FileSpanExporter without errors."""
        client = BeaconClient(
            file_directory=str(temp_span_directory),
        )

        assert isinstance(client.transport, FileTransport)
        assert client.config.endpoint == ''

    def test_init_with_env_vars(self):
        """Test initialization with environment variables."""
        with patch.dict(
            os.environ,
            {
                "BEACON_ENDPOINT": "https://env.test.com",
                "BEACON_API_KEY": "env-key",
                "BEACON_SESSION_ID": "env-session",
                "BEACON_SERVICE_NAME": "env-service",
            },
        ):
            client = BeaconClient(auto_instrument_opentelemetry=False)

            assert client.config.endpoint == "https://env.test.com"
            assert client.config.api_key == "env-key"
            assert client.config.session_id == "env-session"
            assert client.config.service_name == "env-service"

    def test_init_params_override_env_vars(self):
        """Test that constructor parameters override environment variables."""
        with patch.dict(
            os.environ,
            {
                "BEACON_ENDPOINT": "https://env.test.com",
                "BEACON_API_KEY": "env-key",
                "BEACON_SERVICE_NAME": "env-service",
            },
        ):
            client = BeaconClient(
                endpoint="https://param.test.com",
                api_key="param-key",
                service_name="param-service",
                auto_instrument_opentelemetry=False,
            )

            assert client.config.endpoint == "https://param.test.com"
            assert client.config.api_key == "param-key"
            assert client.config.service_name == "param-service"

    def test_init_with_verify_ssl(self):
        """Test initialization with SSL verification options."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            verify=False,
            auto_instrument_opentelemetry=False,
        )

        assert client.config.verify is False
        assert client.transport.verify is False

    def test_init_with_verify_env_var(self):
        """Test SSL verification from environment variable."""
        with patch.dict(os.environ, {"BEACON_VERIFY": "false"}):
            client = BeaconClient(
                endpoint="https://api.test.com",
                auto_instrument_opentelemetry=False,
            )
            assert client.config.verify is False

    def test_init_with_custom_headers(self):
        """Test initialization with custom headers."""
        custom_headers = {"X-Custom-Header": "test-value"}
        client = BeaconClient(
            endpoint="https://api.test.com",
            headers=custom_headers,
            auto_instrument_opentelemetry=False,
        )

        assert "X-Custom-Header" in client.transport.headers
        assert client.transport.headers["X-Custom-Header"] == "test-value"

    def test_init_sets_current_client(self):
        """Test that initialization sets the current client in context."""
        from lumenova_beacon.core.client import get_client

        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=False,
        )

        assert get_client() == client

    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_init_with_auto_instrument(self, mock_setup):
        """Test initialization with auto instrumentation enabled."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=True,
        )

        mock_setup.assert_called_once()

    def test_init_without_auto_instrument(self):
        """Test initialization with auto instrumentation disabled."""
        with patch(
            "lumenova_beacon.core.client.BeaconClient._setup_opentelemetry"
        ) as mock_setup:
            client = BeaconClient(
                endpoint="https://api.test.com",
                auto_instrument_opentelemetry=False,
            )

            mock_setup.assert_not_called()


class TestBeaconClientSpanCreation:
    """Test BeaconClient span creation methods."""

    @pytest.fixture
    def client(self):
        """Create a test client."""
        return BeaconClient(
            endpoint="https://api.test.com",
            session_id="test-session",
            auto_instrument_opentelemetry=False,
        )

    def test_create_span_basic(self, client):
        """Test creating a basic span."""
        span = client.create_span("test_operation")

        assert span.name == "test_operation"
        assert span.kind == SpanKind.INTERNAL
        assert span.span_type == SpanType.SPAN
        assert span.session_id == "test-session"
        assert span.trace_id is not None
        assert span.span_id is not None
        assert span.parent_id is None

    def test_create_span_with_custom_kind_and_type(self, client):
        """Test creating a span with custom kind and type."""
        span = client.create_span(
            "llm_call",
            kind=SpanKind.CLIENT,
            span_type=SpanType.GENERATION,
        )

        assert span.name == "llm_call"
        assert span.kind == SpanKind.CLIENT
        assert span.span_type == SpanType.GENERATION

    def test_create_span_with_explicit_session_id(self, client):
        """Test creating a span with explicit session ID."""
        span = client.create_span(
            "test_op",
            session_id="custom-session",
        )

        assert span.session_id == "custom-session"

    def test_create_span_with_parent_context(self, client):
        """Test creating a span with parent context."""
        # Create parent span and set it in context
        parent_span = client.create_span("parent_operation")
        parent_span.start()

        from lumenova_beacon.tracing.trace import set_current_span

        set_current_span(parent_span)

        # Create child span
        child_span = client.create_span("child_operation")

        assert child_span.parent_id == parent_span.span_id
        assert child_span.trace_id == parent_span.trace_id
        assert child_span.session_id == parent_span.session_id

    def test_create_span_without_auto_parent(self, client):
        """Test creating a span without auto-parenting.

        When auto_parent=False, the span should not have a parent_id set,
        but it may still share the trace_id from the current context.
        """
        # Create parent span and set it in context
        parent_span = client.create_span("parent_operation")

        from lumenova_beacon.tracing.trace import set_current_span

        set_current_span(parent_span)

        # Create child span with auto_parent=False
        child_span = client.create_span("child_operation", auto_parent=False)

        # With auto_parent=False, no parent_id is set
        assert child_span.parent_id is None
        # Note: trace_id can still be inherited from context
        # The key difference is that there's no parent-child relationship

    def test_trace_context_manager(self, client):
        """Test creating a trace context manager."""
        trace_ctx = client.trace("operation_name")

        assert isinstance(trace_ctx, TraceContext)
        assert trace_ctx.span.name == "operation_name"
        assert trace_ctx.client == client

    def test_trace_context_manager_starts_span(self, client):
        """Test that trace context manager starts the span."""
        trace_ctx = client.trace("operation_name")

        assert trace_ctx.span.start_time is not None

    def test_trace_context_manager_with_params(self, client):
        """Test trace context manager with custom parameters."""
        trace_ctx = client.trace(
            "llm_call",
            kind=SpanKind.CLIENT,
            span_type=SpanType.GENERATION,
        )

        assert trace_ctx.span.kind == SpanKind.CLIENT
        assert trace_ctx.span.span_type == SpanType.GENERATION


class TestBeaconClientSampling:
    """Test BeaconClient sampling methods."""

    @pytest.fixture
    def client(self):
        """Create a test client."""
        return BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=False,
        )

    def test_should_sample_when_enabled(self, client):
        """Test should_sample returns True when enabled."""
        assert client.should_sample() is True

    def test_should_sample_when_disabled(self):
        """Test should_sample returns False when disabled."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            enabled=False,
            auto_instrument_opentelemetry=False,
        )

        assert client.should_sample() is False


class TestBeaconClientUtilityMethods:
    """Test BeaconClient utility methods."""

    def test_get_base_url_http_transport(self):
        """Test getting base URL with HTTP transport."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=False,
        )

        assert client.get_base_url() == "https://api.test.com"

    def test_get_base_url_file_transport_raises_error(self, temp_span_directory):
        """Test that get_base_url raises error with file transport."""
        client = BeaconClient(
            file_directory=str(temp_span_directory),
            auto_instrument_opentelemetry=False,
        )

        with pytest.raises(ConfigurationError) as exc_info:
            client.get_base_url()

        assert "HTTPTransport" in str(exc_info.value)

    def test_flush_method(self):
        """Test flush method (currently no-op)."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=False,
        )

        # Should not raise any errors
        client.flush()


class TestGetClient:
    """Test get_client() function."""

    def test_get_client_returns_existing(self):
        """Test that get_client returns existing client."""
        from lumenova_beacon.core.client import get_client

        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=False,
        )

        retrieved = get_client()
        assert retrieved == client

    def test_get_client_creates_new_when_none(self):
        """Test that get_client creates new client when none exists."""
        from lumenova_beacon.core.client import _current_client, get_client

        # Clear the current client
        _current_client.set(None)

        # Mock the environment to provide required config
        with patch.dict(os.environ, {"BEACON_ENDPOINT": "https://api.test.com"}):
            with patch(
                "lumenova_beacon.core.client.BeaconClient._setup_opentelemetry"
            ):
                retrieved = get_client()
                assert isinstance(retrieved, BeaconClient)


class TestOpenTelemetrySetup:
    """Test OpenTelemetry auto-instrumentation setup."""

    def test_setup_opentelemetry_runs_without_error(self):
        """Test that OpenTelemetry setup completes without error."""
        # Simply verify the client can be created with auto_instrument=True
        # The setup method should handle all cases gracefully
        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=True,
        )

        # Client should be created successfully
        assert client is not None
        assert client.config.endpoint == "https://api.test.com"

    def test_setup_opentelemetry_disabled(self):
        """Test that OpenTelemetry setup can be disabled."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=False,
        )

        # Client should be created successfully
        assert client is not None

    def test_manual_setup_opentelemetry_call(self):
        """Test that _setup_opentelemetry can be called manually."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=False,
        )

        # Calling setup manually should not raise
        client._setup_opentelemetry()

    def test_setup_opentelemetry_warns_when_not_installed(self, caplog):
        """Test that a warning is logged when OpenTelemetry is not installed."""
        import lumenova_beacon.core.client as client_module

        with patch.object(client_module, '_beacon_global_exporter_added', False):
            with patch.dict("sys.modules", {"opentelemetry": None, "opentelemetry.trace": None,
                                             "opentelemetry.sdk.trace": None,
                                             "opentelemetry.sdk.trace.export": None,
                                             "opentelemetry.sdk.resources": None}):
                with caplog.at_level(logging.WARNING, logger="lumenova_beacon.core.client"):
                    client = BeaconClient(
                        endpoint="https://api.test.com",
                        auto_instrument_opentelemetry=True,
                    )

        assert any(
            "OpenTelemetry SDK not installed" in record.message
            and record.levelno == logging.WARNING
            for record in caplog.records
        )

    def test_setup_litellm_warns_when_not_installed(self, caplog):
        """Test that a warning is logged when litellm is not installed."""
        with patch.dict("sys.modules", {"litellm": None}):
            with caplog.at_level(logging.WARNING, logger="lumenova_beacon.core.client"):
                client = BeaconClient(
                    endpoint="https://api.test.com",
                    auto_instrument_opentelemetry=False,
                    auto_instrument_litellm=True,
                )

        assert any(
            "litellm not installed" in record.message
            and record.levelno == logging.WARNING
            for record in caplog.records
        )


class TestEagerExportConfig:
    """Test eager_export configuration."""

    def test_eager_export_defaults_to_true(self):
        """Test that eager_export defaults to True."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=False,
        )
        assert client.config.eager_export is True

    def test_eager_export_explicit_false(self):
        """Test that eager_export can be set to False explicitly."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            eager_export=False,
            auto_instrument_opentelemetry=False,
        )
        assert client.config.eager_export is False

    def test_eager_export_explicit_true(self):
        """Test that eager_export can be set to True explicitly."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            eager_export=True,
            auto_instrument_opentelemetry=False,
        )
        assert client.config.eager_export is True

    def test_eager_export_env_var_false(self):
        """Test eager_export resolved from BEACON_EAGER_EXPORT=false."""
        with patch.dict(os.environ, {"BEACON_EAGER_EXPORT": "false"}):
            client = BeaconClient(
                endpoint="https://api.test.com",
                auto_instrument_opentelemetry=False,
            )
            assert client.config.eager_export is False

    def test_eager_export_env_var_zero(self):
        """Test eager_export resolved from BEACON_EAGER_EXPORT=0."""
        with patch.dict(os.environ, {"BEACON_EAGER_EXPORT": "0"}):
            client = BeaconClient(
                endpoint="https://api.test.com",
                auto_instrument_opentelemetry=False,
            )
            assert client.config.eager_export is False

    def test_eager_export_env_var_no(self):
        """Test eager_export resolved from BEACON_EAGER_EXPORT=no."""
        with patch.dict(os.environ, {"BEACON_EAGER_EXPORT": "no"}):
            client = BeaconClient(
                endpoint="https://api.test.com",
                auto_instrument_opentelemetry=False,
            )
            assert client.config.eager_export is False

    def test_eager_export_env_var_true(self):
        """Test eager_export resolved from BEACON_EAGER_EXPORT=true."""
        with patch.dict(os.environ, {"BEACON_EAGER_EXPORT": "true"}):
            client = BeaconClient(
                endpoint="https://api.test.com",
                auto_instrument_opentelemetry=False,
            )
            assert client.config.eager_export is True

    def test_eager_export_param_overrides_env_var(self):
        """Test that explicit param overrides env var."""
        with patch.dict(os.environ, {"BEACON_EAGER_EXPORT": "false"}):
            client = BeaconClient(
                endpoint="https://api.test.com",
                eager_export=True,
                auto_instrument_opentelemetry=False,
            )
            assert client.config.eager_export is True

    def test_trace_context_receives_eager_export(self):
        """Test that client.trace() passes eager_export to TraceContext."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            eager_export=True,
            auto_instrument_opentelemetry=False,
        )
        trace_ctx = client.trace("test_op")
        assert trace_ctx.eager_export is True

    def test_trace_context_receives_eager_export_false(self):
        """Test that client.trace() passes eager_export=False to TraceContext."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            eager_export=False,
            auto_instrument_opentelemetry=False,
        )
        trace_ctx = client.trace("test_op")
        assert trace_ctx.eager_export is False


class TestEnvironmentConfig:
    """Test environment configuration."""

    def test_environment_explicit_param(self):
        """Test that environment can be set via constructor param."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            environment="production",
            auto_instrument_opentelemetry=False,
        )
        assert client.config.environment == "production"

    def test_environment_env_var_fallback(self):
        """Test that environment falls back to BEACON_ENVIRONMENT env var."""
        with patch.dict(os.environ, {"BEACON_ENVIRONMENT": "staging"}):
            client = BeaconClient(
                endpoint="https://api.test.com",
                auto_instrument_opentelemetry=False,
            )
            assert client.config.environment == "staging"

    def test_environment_param_overrides_env_var(self):
        """Test that explicit param overrides BEACON_ENVIRONMENT env var."""
        with patch.dict(os.environ, {"BEACON_ENVIRONMENT": "staging"}):
            client = BeaconClient(
                endpoint="https://api.test.com",
                environment="production",
                auto_instrument_opentelemetry=False,
            )
            assert client.config.environment == "production"

    def test_environment_defaults_to_none(self):
        """Test that environment defaults to None when not set."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=False,
        )
        assert client.config.environment is None

    def test_environment_propagated_to_spans(self):
        """Test that environment is set as span attribute on created spans."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            environment="production",
            auto_instrument_opentelemetry=False,
        )
        span = client.create_span("test_op")
        assert span.attributes.get("deployment.environment.name") == "production"

    def test_environment_not_set_on_spans_when_none(self):
        """Test that no environment attribute is set when environment is None."""
        client = BeaconClient(
            endpoint="https://api.test.com",
            auto_instrument_opentelemetry=False,
        )
        span = client.create_span("test_op")
        assert "deployment.environment.name" not in span.attributes

    def test_environment_in_env_var_init_test(self):
        """Test that BEACON_ENVIRONMENT is picked up alongside other env vars."""
        with patch.dict(
            os.environ,
            {
                "BEACON_ENDPOINT": "https://env.test.com",
                "BEACON_API_KEY": "env-key",
                "BEACON_ENVIRONMENT": "development",
            },
        ):
            client = BeaconClient(auto_instrument_opentelemetry=False)
            assert client.config.environment == "development"


class TestBeaconIsolatedEnvVar:
    """Test BEACON_ISOLATED environment variable support."""

    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_isolated_defaults_to_false(self, mock_setup):
        BeaconClient(endpoint="https://api.test.com")
        mock_setup.assert_called_once_with(isolated=False)

    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_isolated_env_var_true(self, mock_setup):
        with patch.dict(os.environ, {"BEACON_ISOLATED": "true"}):
            BeaconClient(endpoint="https://api.test.com")
        mock_setup.assert_called_once_with(isolated=True)

    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_isolated_env_var_1(self, mock_setup):
        with patch.dict(os.environ, {"BEACON_ISOLATED": "1"}):
            BeaconClient(endpoint="https://api.test.com")
        mock_setup.assert_called_once_with(isolated=True)

    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_isolated_env_var_yes(self, mock_setup):
        with patch.dict(os.environ, {"BEACON_ISOLATED": "yes"}):
            BeaconClient(endpoint="https://api.test.com")
        mock_setup.assert_called_once_with(isolated=True)

    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_isolated_param_overrides_env_var_false(self, mock_setup):
        with patch.dict(os.environ, {"BEACON_ISOLATED": "false"}):
            BeaconClient(endpoint="https://api.test.com", isolated=True)
        mock_setup.assert_called_once_with(isolated=True)

    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_isolated_env_var_false(self, mock_setup):
        with patch.dict(os.environ, {"BEACON_ISOLATED": "false"}):
            BeaconClient(endpoint="https://api.test.com")
        mock_setup.assert_called_once_with(isolated=False)


class TestApiKeyAwsResolution:
    """Test API key resolution cascade: param > env > AWS."""

    def test_api_key_param_takes_precedence_over_aws(self):
        with patch.dict(os.environ, {"BEACON_AWS_SECRET_NAME": "my-secret"}):
            with patch("lumenova_beacon.core.secrets.resolve_aws_secret") as mock_aws:
                client = BeaconClient(
                    endpoint="https://api.test.com",
                    api_key="explicit-key",
                    auto_instrument_opentelemetry=False,
                )
                mock_aws.assert_not_called()
                assert client.config.api_key == "explicit-key"

    def test_api_key_env_var_takes_precedence_over_aws(self):
        with patch.dict(os.environ, {
            "BEACON_ENDPOINT": "https://api.test.com",
            "BEACON_API_KEY": "env-key",
            "BEACON_AWS_SECRET_NAME": "my-secret",
        }):
            with patch("lumenova_beacon.core.secrets.resolve_aws_secret") as mock_aws:
                client = BeaconClient(auto_instrument_opentelemetry=False)
                mock_aws.assert_not_called()
                assert client.config.api_key == "env-key"

    @patch("lumenova_beacon.core.secrets.resolve_aws_secret", return_value="aws-key")
    def test_api_key_falls_through_to_aws(self, mock_aws):
        with patch.dict(os.environ, {
            "BEACON_ENDPOINT": "https://api.test.com",
            "BEACON_AWS_SECRET_NAME": "my-secret",
        }, clear=False):
            # Remove BEACON_API_KEY if present
            os.environ.pop("BEACON_API_KEY", None)
            client = BeaconClient(auto_instrument_opentelemetry=False)
            assert client.config.api_key == "aws-key"

    @patch("lumenova_beacon.core.secrets.resolve_aws_secret", return_value=None)
    def test_api_key_aws_failure_returns_none(self, mock_aws):
        with patch.dict(os.environ, {
            "BEACON_ENDPOINT": "https://api.test.com",
            "BEACON_AWS_SECRET_NAME": "my-secret",
        }, clear=False):
            os.environ.pop("BEACON_API_KEY", None)
            client = BeaconClient(auto_instrument_opentelemetry=False)
            assert client.config.api_key is None


class TestExtraOtlpEndpoints:
    """Test BEACON_EXTRA_OTLP_ENDPOINTS environment variable support."""

    @patch("lumenova_beacon.core.client.BeaconClient._setup_additional_otlp_endpoints")
    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_no_additional_endpoints_by_default(self, mock_otel, mock_extra):
        BeaconClient(endpoint="https://api.test.com")
        mock_extra.assert_called_once()

    @patch("lumenova_beacon.core.client.BeaconClient.add_span_exporter")
    @patch("opentelemetry.exporter.otlp.proto.grpc.trace_exporter.OTLPSpanExporter")
    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_single_additional_endpoint(self, mock_otel, mock_exporter_cls, mock_add):
        with patch.dict(os.environ, {
            "BEACON_EXTRA_OTLP_ENDPOINTS": "http://collector:4317",
        }):
            BeaconClient(endpoint="https://api.test.com")
        mock_exporter_cls.assert_called_once()
        mock_add.assert_called_once()

    @patch("lumenova_beacon.core.client.BeaconClient.add_span_exporter")
    @patch("opentelemetry.exporter.otlp.proto.grpc.trace_exporter.OTLPSpanExporter")
    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_multiple_additional_endpoints(self, mock_otel, mock_exporter_cls, mock_add):
        with patch.dict(os.environ, {
            "BEACON_EXTRA_OTLP_ENDPOINTS": "http://collector1:4317,http://collector2:4317",
        }):
            BeaconClient(endpoint="https://api.test.com")
        assert mock_exporter_cls.call_count == 2
        assert mock_add.call_count == 2

    @patch("lumenova_beacon.core.client.BeaconClient.add_span_exporter")
    @patch("opentelemetry.exporter.otlp.proto.grpc.trace_exporter.OTLPSpanExporter")
    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_authorization_header_excluded(self, mock_otel, mock_exporter_cls, mock_add):
        with patch.dict(os.environ, {
            "BEACON_EXTRA_OTLP_ENDPOINTS": "http://collector:4317",
        }):
            BeaconClient(endpoint="https://api.test.com", api_key="secret-key")
        mock_exporter_cls.assert_called_once()
        call_headers = mock_exporter_cls.call_args[1]["headers"]
        assert "Authorization" not in call_headers
        assert "authorization" not in call_headers

    @patch("lumenova_beacon.core.client.BeaconClient.add_span_exporter")
    @patch("lumenova_beacon.core.client.BeaconClient._setup_opentelemetry")
    def test_empty_env_var_ignored(self, mock_otel, mock_add):
        with patch.dict(os.environ, {"BEACON_EXTRA_OTLP_ENDPOINTS": ""}):
            BeaconClient(endpoint="https://api.test.com")
        mock_add.assert_not_called()

    @patch("lumenova_beacon.core.client.BeaconClient._setup_additional_otlp_endpoints")
    def test_endpoints_not_added_when_otel_disabled(self, mock_extra):
        with patch.dict(os.environ, {
            "BEACON_EXTRA_OTLP_ENDPOINTS": "http://collector:4317",
        }):
            BeaconClient(
                endpoint="https://api.test.com",
                auto_instrument_opentelemetry=False,
            )
        mock_extra.assert_not_called()
