"""Unit tests for GCP Cloud Logging exporter."""

import pytest
import sys
from unittest.mock import Mock, patch, MagicMock
from mca_sdk.exporters.gcp_logging import CloudLoggingExporter
from opentelemetry.sdk._logs.export import LogExportResult


class TestCloudLoggingExporter:
    """Test CloudLoggingExporter functionality."""

    def test_exporter_initialization(self):
        """Test exporter initializes with correct parameters."""
        # Mock the import
        mock_cloud_logging = MagicMock()
        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            exporter = CloudLoggingExporter(
                project_id="test-project",
                log_name="test-log",
                resource_type="k8s_container",
            )

            assert exporter.project_id == "test-project"
            assert exporter.log_name == "test-log"
            assert exporter.resource_type == "k8s_container"

    def test_exporter_requires_google_cloud_logging(self):
        """Test that ImportError is raised if google-cloud-logging not installed."""
        with patch.dict("sys.modules", {"google.cloud.logging": None}):
            with pytest.raises(ImportError, match="google-cloud-logging is required"):
                CloudLoggingExporter(project_id="test-project", log_name="test-log")

    def test_export_empty_batch(self):
        """Test exporting empty batch returns success."""
        mock_cloud_logging = MagicMock()
        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            exporter = CloudLoggingExporter(project_id="test-project", log_name="test-log")

            result = exporter.export([])
            assert result == LogExportResult.SUCCESS

    def test_export_single_log_record(self):
        """Test exporting a single log record."""
        mock_cloud_logging = MagicMock()
        mock_client = Mock()
        mock_logger = Mock()
        mock_client.logger.return_value = mock_logger
        mock_cloud_logging.Client.return_value = mock_client

        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            exporter = CloudLoggingExporter(project_id="test-project", log_name="test-log")

            log_record = Mock()
            log_record.body = Mock(value="Test message")
            log_record.severity_text = "INFO"
            log_record.attributes = {"key": "value"}
            log_record.resource = Mock(attributes={"service.name": "test-service"})

            result = exporter.export([log_record])

            assert result == LogExportResult.SUCCESS
            mock_logger.log_struct.assert_called_once()

    def test_severity_mapping(self):
        """Test OTel severity to Cloud Logging severity mapping."""
        mock_cloud_logging = MagicMock()
        mock_client = Mock()
        mock_logger = Mock()
        mock_client.logger.return_value = mock_logger
        mock_cloud_logging.Client.return_value = mock_client

        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            exporter = CloudLoggingExporter(project_id="test-project", log_name="test-log")

            severities = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]

            for severity in severities:
                log_record = Mock()
                log_record.body = Mock(value=f"{severity} message")
                log_record.severity_text = severity
                log_record.attributes = {}
                log_record.resource = Mock(attributes={})

                exporter.export([log_record])

            assert mock_logger.log_struct.call_count == len(severities)

    def test_export_with_credentials(self):
        """Test exporter uses provided credentials."""
        mock_cloud_logging = MagicMock()
        mock_client = Mock()
        mock_cloud_logging.Client.return_value = mock_client

        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            mock_creds = Mock()
            exporter = CloudLoggingExporter(
                project_id="test-project", log_name="test-log", credentials=mock_creds
            )

            # Trigger client initialization
            exporter._ensure_client()

            mock_cloud_logging.Client.assert_called_once_with(
                project="test-project", credentials=mock_creds
            )

    def test_shutdown(self):
        """Test exporter shutdown."""
        mock_cloud_logging = MagicMock()
        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            exporter = CloudLoggingExporter(project_id="test-project", log_name="test-log")

            exporter.shutdown()
            # Should not raise any exceptions

    def test_force_flush(self):
        """Test force flush returns True."""
        mock_cloud_logging = MagicMock()
        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            exporter = CloudLoggingExporter(project_id="test-project", log_name="test-log")

            result = exporter.force_flush()
            assert result is True

    def test_export_returns_failure_on_exception(self):
        """Test export returns FAILURE when exception occurs."""
        mock_cloud_logging = MagicMock()
        mock_client = Mock()
        mock_logger = Mock()
        mock_client.logger.return_value = mock_logger
        mock_cloud_logging.Client.return_value = mock_client

        # Make log_struct raise an exception
        mock_logger.log_struct.side_effect = Exception("Network error")

        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            exporter = CloudLoggingExporter(project_id="test-project", log_name="test-log")

            log_record = Mock()
            log_record.body = Mock(value="Test message")
            log_record.severity_text = "INFO"
            log_record.attributes = {}
            log_record.resource = Mock(attributes={})

            result = exporter.export([log_record])

            assert result == LogExportResult.FAILURE

    def test_export_handles_auth_failure(self):
        """Test export returns FAILURE and logs auth error on 401."""
        mock_cloud_logging = MagicMock()
        mock_client = Mock()
        mock_logger = Mock()
        mock_client.logger.return_value = mock_logger
        mock_cloud_logging.Client.return_value = mock_client

        # Make log_struct raise 401 Unauthorized
        mock_logger.log_struct.side_effect = Exception("401 Unauthorized")

        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            exporter = CloudLoggingExporter(project_id="test-project", log_name="test-log")

            log_record = Mock()
            log_record.body = Mock(value="Test message")
            log_record.severity_text = "INFO"
            log_record.attributes = {}
            log_record.resource = Mock(attributes={})

            result = exporter.export([log_record])

            assert result == LogExportResult.FAILURE

    def test_export_handles_permission_denied(self):
        """Test export returns FAILURE and logs permission error on 403."""
        mock_cloud_logging = MagicMock()
        mock_client = Mock()
        mock_logger = Mock()
        mock_client.logger.return_value = mock_logger
        mock_cloud_logging.Client.return_value = mock_client

        # Make log_struct raise 403 Forbidden
        mock_logger.log_struct.side_effect = Exception("403 Forbidden: Permission denied")

        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            exporter = CloudLoggingExporter(project_id="test-project", log_name="test-log")

            log_record = Mock()
            log_record.body = Mock(value="Test message")
            log_record.severity_text = "INFO"
            log_record.attributes = {}
            log_record.resource = Mock(attributes={})

            result = exporter.export([log_record])

            assert result == LogExportResult.FAILURE

    def test_export_handles_quota_exceeded(self):
        """Test export returns FAILURE and logs quota error on 429."""
        mock_cloud_logging = MagicMock()
        mock_client = Mock()
        mock_logger = Mock()
        mock_client.logger.return_value = mock_logger
        mock_cloud_logging.Client.return_value = mock_client

        # Make log_struct raise 429 Quota exceeded
        mock_logger.log_struct.side_effect = Exception("429 Quota exceeded")

        with patch.dict("sys.modules", {"google.cloud.logging": mock_cloud_logging}):
            exporter = CloudLoggingExporter(project_id="test-project", log_name="test-log")

            log_record = Mock()
            log_record.body = Mock(value="Test message")
            log_record.severity_text = "INFO"
            log_record.attributes = {}
            log_record.resource = Mock(attributes={})

            result = exporter.export([log_record])

            assert result == LogExportResult.FAILURE
