"""Integration tests for GCP authentication with exporters.

These tests document how GCP exporters should use the authentication system
when Stories 6.1, 6.2, and 6.3 are implemented.
"""

import json
import tempfile
from unittest.mock import Mock, patch

import pytest

from mca_sdk.config import MCAConfig
from mca_sdk.core.gcp_auth import get_google_credentials, get_credentials_for_config

# Sample valid service account JSON
VALID_SERVICE_ACCOUNT = {
    "type": "service_account",
    "project_id": "test-project",
    "private_key_id": "key123",
    "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEv...test...==\n-----END PRIVATE KEY-----\n",
    "client_email": "test@test-project.iam.gserviceaccount.com",
    "client_id": "123456789",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test%40test-project.iam.gserviceaccount.com",
}


class TestExporterIntegration:
    """Test how GCP exporters should integrate with authentication."""

    @patch("google.oauth2.service_account.Credentials.from_service_account_info")
    def test_cloud_monitoring_exporter_pattern(self, mock_from_info):
        """Document pattern for Cloud Monitoring exporter (Story 6.1)."""
        # Mock google.auth credentials
        mock_google_creds = Mock()
        mock_google_creds.project_id = "test-project"
        mock_from_info.return_value = mock_google_creds

        # Setup config with credentials
        config = MCAConfig(
            service_name="test-service",
            gcp_credentials_json=json.dumps(VALID_SERVICE_ACCOUNT),
        )

        # This is how Cloud Monitoring exporter should get credentials
        credentials = get_google_credentials(config)

        assert credentials is not None
        assert credentials == mock_google_creds

        # Exporter would then use credentials like:
        # from google.cloud import monitoring_v3
        # client = monitoring_v3.MetricServiceClient(credentials=credentials)

    @patch("google.oauth2.service_account.Credentials.from_service_account_info")
    def test_cloud_logging_exporter_pattern(self, mock_from_info):
        """Document pattern for Cloud Logging exporter (Story 6.2)."""
        # Mock google.auth credentials
        mock_google_creds = Mock()
        mock_google_creds.project_id = "test-project"
        mock_from_info.return_value = mock_google_creds

        # Setup config with credentials
        config = MCAConfig(
            service_name="test-service",
            gcp_credentials_json=json.dumps(VALID_SERVICE_ACCOUNT),
        )

        # This is how Cloud Logging exporter should get credentials
        credentials = get_google_credentials(config)

        assert credentials is not None
        assert credentials == mock_google_creds

        # Exporter would then use credentials like:
        # from google.cloud import logging
        # client = logging.Client(credentials=credentials, project=credentials.project_id)

    @patch("google.oauth2.service_account.Credentials.from_service_account_info")
    def test_cloud_trace_exporter_pattern(self, mock_from_info):
        """Document pattern for Cloud Trace exporter (Story 6.3)."""
        # Mock google.auth credentials
        mock_google_creds = Mock()
        mock_google_creds.project_id = "test-project"
        mock_from_info.return_value = mock_google_creds

        # Setup config with credentials
        config = MCAConfig(
            service_name="test-service",
            gcp_credentials_json=json.dumps(VALID_SERVICE_ACCOUNT),
        )

        # This is how Cloud Trace exporter should get credentials
        credentials = get_google_credentials(config)

        assert credentials is not None
        assert credentials == mock_google_creds

        # Exporter would then use credentials like:
        # from google.cloud import trace_v2
        # client = trace_v2.TraceServiceClient(credentials=credentials)

    def test_exporter_handles_missing_credentials_gracefully(self):
        """Test that exporters can handle missing credentials."""
        # Config without credentials
        config = MCAConfig(service_name="test-service")

        with patch("google.auth.default", side_effect=Exception("ADC not available")):
            credentials = get_google_credentials(config)

        # Should return None when credentials not available
        assert credentials is None

        # Exporters should handle this case by:
        # - Logging a warning
        # - Either falling back to ADC
        # - Or disabling GCP export functionality

    @patch("google.oauth2.service_account.Credentials.from_service_account_info")
    def test_all_exporters_use_same_credentials(self, mock_from_info):
        """Test that all exporters can share the same credentials instance."""
        # Mock google.auth credentials
        mock_google_creds = Mock()
        mock_google_creds.project_id = "test-project"
        mock_from_info.return_value = mock_google_creds

        config = MCAConfig(
            service_name="test-service",
            gcp_credentials_json=json.dumps(VALID_SERVICE_ACCOUNT),
        )

        # All three exporters should be able to get credentials
        monitoring_creds = get_google_credentials(config)
        logging_creds = get_google_credentials(config)
        trace_creds = get_google_credentials(config)

        # All should get the same credentials instance (or equivalent)
        assert monitoring_creds is not None
        assert logging_creds is not None
        assert trace_creds is not None

    @patch("google.oauth2.service_account.Credentials.from_service_account_info")
    def test_credentials_have_required_scopes(self, mock_from_info):
        """Test that credentials include all required GCP scopes."""
        # Mock to capture scopes argument
        mock_google_creds = Mock()
        mock_from_info.return_value = mock_google_creds

        config = MCAConfig(
            service_name="test-service",
            gcp_credentials_json=json.dumps(VALID_SERVICE_ACCOUNT),
        )

        # Get credentials
        get_credentials_for_config(config)

        # Verify scopes were requested
        call_args = mock_from_info.call_args
        scopes = call_args[1].get("scopes", [])

        required_scopes = [
            "https://www.googleapis.com/auth/monitoring.write",
            "https://www.googleapis.com/auth/logging.write",
            "https://www.googleapis.com/auth/trace.append",
        ]

        for scope in required_scopes:
            assert scope in scopes, f"Missing required scope: {scope}"


class TestCredentialSecurityInExporters:
    """Test security aspects of credential handling in exporters."""

    @patch("google.oauth2.service_account.Credentials.from_service_account_info")
    def test_credentials_not_logged_by_exporters(self, mock_from_info):
        """Test that exporters don't accidentally log credentials."""
        mock_google_creds = Mock()
        mock_google_creds.__repr__ = Mock(return_value="<Credentials redacted>")
        mock_from_info.return_value = mock_google_creds

        config = MCAConfig(
            service_name="test-service",
            gcp_credentials_json=json.dumps(VALID_SERVICE_ACCOUNT),
        )

        credentials = get_google_credentials(config)

        # Exporters should use credentials without logging them
        # repr should not expose raw credentials
        assert "PRIVATE KEY" not in repr(credentials)

    @patch("google.oauth2.service_account.Credentials.from_service_account_info")
    def test_credentials_not_in_exporter_errors(self, mock_from_info):
        """Test that credential details don't leak in exporter errors."""
        mock_google_creds = Mock()
        mock_from_info.return_value = mock_google_creds

        config = MCAConfig(
            service_name="test-service",
            gcp_credentials_json=json.dumps(VALID_SERVICE_ACCOUNT),
        )

        credentials = get_google_credentials(config)

        # Simulate exporter error
        # Credentials should not be in error message
        error_msg = f"Failed to export metrics using {credentials}"
        assert "PRIVATE KEY" not in error_msg
        assert "-----BEGIN" not in error_msg
