"""Integration tests for GCP Cloud Trace exporter.

NOTE: Most tests use mocking (@patch.dict) rather than real GCP API calls.
These verify SDK integration and configuration but not actual Cloud Trace API behavior.
For true end-to-end testing, set GCP_TEST_PROJECT_ID and GCP_TEST_CREDENTIALS_PATH
environment variables to run test_gcp_trace_end_to_end() against real GCP.
"""

import os
import pytest
from unittest.mock import Mock, patch, MagicMock
from mca_sdk import MCAClient
from mca_sdk.config import MCAConfig


@pytest.mark.skipif(
    not os.getenv("GCP_TEST_PROJECT_ID"),
    reason="GCP project not configured for testing",
)
def test_gcp_trace_end_to_end():
    """Test end-to-end span export to GCP Cloud Trace."""
    config = MCAConfig(
        service_name="test-service",
        model_id="test-model",
        team_name="test-team",
        gcp_trace_enabled=True,
        gcp_project_id=os.getenv("GCP_TEST_PROJECT_ID"),
        gcp_credentials_path=os.getenv("GCP_TEST_CREDENTIALS_PATH"),
    )

    client = MCAClient(config=config)

    # Create test span
    with client.trace("test.operation") as span:
        span.set_attribute("test_key", "test_value")

    # Force flush
    client.shutdown()

    assert True


@patch.dict("sys.modules", {"google.cloud.trace_v2": MagicMock()})
def test_gcp_trace_with_otlp():
    """Test GCP Cloud Trace works alongside OTLP exporter."""
    with patch("mca_sdk.core.gcp_auth.get_google_credentials") as mock_creds:
        with patch("mca_sdk.core.gcp_auth.get_credentials_for_config") as mock_get_creds:
            # Mock credentials
            mock_creds.return_value = Mock()
            mock_creds_obj = Mock()
            mock_creds_obj.project_id = "test-project"
            mock_get_creds.return_value = mock_creds_obj

            config = MCAConfig(
                service_name="test-service",
                model_id="test-model",
                team_name="test-team",
                collector_endpoint="http://localhost:4318",
                gcp_trace_enabled=True,
                gcp_project_id="test-project",
            )

            client = MCAClient(config=config)

            # Create test span - should go to both exporters
            with client.trace("test.operation") as span:
                span.set_attribute("test_key", "test_value")

            # Verify GCP exporter is configured
            # Note: _span_exporter is only set when buffering is enabled
            # Here we verify the GCP exporter was added via span processor
            assert client._gcp_trace_exporter is not None  # GCP exporter
            assert len(client._tracer_provider._active_span_processor._span_processors) >= 1

            client.shutdown()


def test_gcp_trace_disabled():
    """Test that GCP trace exporter is not created when disabled."""
    config = MCAConfig(
        service_name="test-service",
        model_id="test-model",
        team_name="test-team",
        gcp_trace_enabled=False,
    )

    client = MCAClient(config=config)

    # Verify GCP exporter is not created
    assert client._gcp_trace_exporter is None

    client.shutdown()


def test_gcp_trace_missing_credentials():
    """Test error handling when GCP credentials are missing."""
    with patch("mca_sdk.core.gcp_auth.get_google_credentials") as mock_creds:
        mock_creds.return_value = None

        from mca_sdk.utils.exceptions import ConfigurationError

        # Should raise ConfigurationError with either message depending on what fails first
        with pytest.raises(ConfigurationError):
            config = MCAConfig(
                service_name="test-service",
                model_id="test-model",
                team_name="test-team",
                gcp_trace_enabled=True,
                gcp_project_id="test-project",
            )
            client = MCAClient(config=config)


def test_gcp_trace_missing_project_id():
    """Test error handling when project_id cannot be determined."""
    with patch("mca_sdk.core.gcp_auth.get_google_credentials") as mock_creds:
        with patch("mca_sdk.core.gcp_auth.get_credentials_for_config") as mock_get_creds:
            mock_creds.return_value = Mock()
            mock_get_creds.return_value = None

            from mca_sdk.utils.exceptions import ConfigurationError

            with pytest.raises(ConfigurationError, match="Could not determine GCP project_id"):
                config = MCAConfig(
                    service_name="test-service",
                    model_id="test-model",
                    team_name="test-team",
                    gcp_trace_enabled=True,
                )
                client = MCAClient(config=config)


@patch.dict(
    "sys.modules",
    {
        "google.cloud.trace_v2": MagicMock(),
        "google.protobuf.timestamp_pb2": MagicMock(),
    },
)
def test_complete_span_structure():
    """Test complete span structure with status, kind, links, events, and resource attributes."""
    with patch("mca_sdk.core.gcp_auth.get_google_credentials") as mock_creds:
        with patch("mca_sdk.core.gcp_auth.get_credentials_for_config") as mock_get_creds:
            from opentelemetry.trace import StatusCode

            mock_creds.return_value = Mock()
            mock_creds_obj = Mock()
            mock_creds_obj.project_id = "test-project"
            mock_get_creds.return_value = mock_creds_obj

            config = MCAConfig(
                service_name="test-service",
                model_id="test-model",
                team_name="test-team",
                gcp_trace_enabled=True,
                gcp_project_id="test-project",
            )

            client = MCAClient(config=config)

            # Create test span with full structure
            with client.trace("test.operation") as span:
                span.set_attribute("test_key", "test_value")
                span.set_status(StatusCode.OK, "Operation successful")
                span.add_event("test_event", {"event_attr": "event_value"})

            # Verify exporter has resource attributes
            assert client._gcp_trace_exporter is not None
            assert len(client._gcp_trace_exporter._resource_attrs) > 0
            assert "service.name" in client._gcp_trace_exporter._resource_attrs

            client.shutdown()
