"""Tests for event metrics."""

from unittest.mock import MagicMock, patch

from libs.events.metrics import (
    EventMetricsCollector,
    event_consumed_total,
    event_dlq_total,
    event_processing_duration_seconds,
    event_processing_errors_total,
    event_publish_errors_total,
    event_published_total,
    event_publishing_duration_seconds,
    event_retry_total,
    event_schema_validation_errors_total,
    get_event_metrics_registry,
    nats_consumer_lag_messages,
    nats_stream_messages_total,
)


class TestEventMetrics:
    """Test cases for event metrics."""

    def test_get_event_metrics_registry(self) -> None:
        """Test getting the metrics registry."""
        registry = get_event_metrics_registry()
        assert registry is not None

    def test_metrics_exist(self) -> None:
        """Test that all expected metrics are defined."""
        # Publishing metrics
        assert event_published_total is not None
        assert event_publish_errors_total is not None
        assert event_publishing_duration_seconds is not None

        # Consumption metrics
        assert event_consumed_total is not None
        assert event_processing_duration_seconds is not None
        assert event_processing_errors_total is not None

        # DLQ metrics
        assert event_dlq_total is not None
        assert event_retry_total is not None

        # Schema validation metrics
        assert event_schema_validation_errors_total is not None

        # NATS metrics
        assert nats_stream_messages_total is not None
        assert nats_consumer_lag_messages is not None


class TestEventMetricsCollector:
    """Test cases for EventMetricsCollector."""

    def test_record_publish_success(self) -> None:
        """Test recording successful publish."""
        with patch.object(event_published_total, "labels") as mock_labels:
            mock_counter = MagicMock()
            mock_labels.return_value = mock_counter

            EventMetricsCollector.record_publish(
                topic="test.topic",
                duration_seconds=0.05,
                success=True,
            )

            mock_labels.assert_called_once_with(topic="test.topic")
            mock_counter.inc.assert_called_once()

    def test_record_publish_failure(self) -> None:
        """Test recording failed publish."""
        with patch.object(event_publish_errors_total, "labels") as mock_labels:
            mock_counter = MagicMock()
            mock_labels.return_value = mock_counter

            EventMetricsCollector.record_publish(
                topic="test.topic",
                duration_seconds=0.1,
                success=False,
                error_type="ConnectionError",
            )

            mock_labels.assert_called_once_with(
                topic="test.topic", error_type="ConnectionError"
            )
            mock_counter.inc.assert_called_once()

    def test_record_publish_duration(self) -> None:
        """Test recording publish duration."""
        with patch.object(event_publishing_duration_seconds, "labels") as mock_labels:
            mock_histogram = MagicMock()
            mock_labels.return_value = mock_histogram

            duration = 0.123
            EventMetricsCollector.record_publish(
                topic="test.topic",
                duration_seconds=duration,
                success=True,
            )

            mock_labels.assert_called_once_with(topic="test.topic")
            mock_histogram.observe.assert_called_once_with(duration)

    def test_record_consume_success(self) -> None:
        """Test recording successful event consumption."""
        with patch.object(event_consumed_total, "labels") as mock_labels:
            mock_counter = MagicMock()
            mock_labels.return_value = mock_counter

            EventMetricsCollector.record_consume(
                topic="test.topic",
                consumer_group="test-group",
                duration_seconds=0.5,
                success=True,
            )

            mock_labels.assert_called_once_with(
                topic="test.topic", consumer_group="test-group"
            )
            mock_counter.inc.assert_called_once()

    def test_record_consume_failure(self) -> None:
        """Test recording failed event consumption."""
        with patch.object(event_processing_errors_total, "labels") as mock_labels:
            mock_counter = MagicMock()
            mock_labels.return_value = mock_counter

            EventMetricsCollector.record_consume(
                topic="test.topic",
                consumer_group="test-group",
                duration_seconds=1.0,
                success=False,
                error_type="ValidationError",
            )

            mock_labels.assert_called_once_with(
                topic="test.topic",
                consumer_group="test-group",
                error_type="ValidationError",
            )
            mock_counter.inc.assert_called_once()

    def test_record_consume_duration(self) -> None:
        """Test recording consumption duration."""
        with patch.object(event_processing_duration_seconds, "labels") as mock_labels:
            mock_histogram = MagicMock()
            mock_labels.return_value = mock_histogram

            duration = 2.5
            EventMetricsCollector.record_consume(
                topic="test.topic",
                consumer_group="test-group",
                duration_seconds=duration,
                success=True,
            )

            mock_labels.assert_called_once_with(
                topic="test.topic", consumer_group="test-group"
            )
            mock_histogram.observe.assert_called_once_with(duration)

    def test_record_dlq(self) -> None:
        """Test recording DLQ event."""
        with patch.object(event_dlq_total, "labels") as mock_labels:
            mock_counter = MagicMock()
            mock_labels.return_value = mock_counter

            EventMetricsCollector.record_dlq(
                topic="test.topic", error_type="TimeoutError"
            )

            mock_labels.assert_called_once_with(
                topic="test.topic", error_type="TimeoutError"
            )
            mock_counter.inc.assert_called_once()

    def test_record_retry(self) -> None:
        """Test recording retry attempt."""
        with patch.object(event_retry_total, "labels") as mock_labels:
            mock_counter = MagicMock()
            mock_labels.return_value = mock_counter

            EventMetricsCollector.record_retry(topic="test.topic", retry_attempt=2)

            mock_labels.assert_called_once_with(topic="test.topic", retry_attempt="2")
            mock_counter.inc.assert_called_once()

    def test_record_schema_validation_error(self) -> None:
        """Test recording schema validation error."""
        with patch.object(
            event_schema_validation_errors_total, "labels"
        ) as mock_labels:
            mock_counter = MagicMock()
            mock_labels.return_value = mock_counter

            EventMetricsCollector.record_schema_validation_error(
                topic="test.topic", validation_error="missing_required_field"
            )

            mock_labels.assert_called_once_with(
                topic="test.topic", validation_error="missing_required_field"
            )
            mock_counter.inc.assert_called_once()

    def test_record_nats_stream_message(self) -> None:
        """Test recording NATS stream message."""
        with patch.object(nats_stream_messages_total, "labels") as mock_labels:
            mock_counter = MagicMock()
            mock_labels.return_value = mock_counter

            EventMetricsCollector.record_nats_stream_message(
                stream_name="TAX_AGENT_EVENTS"
            )

            mock_labels.assert_called_once_with(stream_name="TAX_AGENT_EVENTS")
            mock_counter.inc.assert_called_once()

    def test_record_consumer_lag(self) -> None:
        """Test recording consumer lag."""
        with patch.object(nats_consumer_lag_messages, "labels") as mock_labels:
            mock_histogram = MagicMock()
            mock_labels.return_value = mock_histogram

            EventMetricsCollector.record_consumer_lag(
                stream_name="TAX_AGENT_EVENTS",
                consumer_group="tax-agent",
                lag_messages=150,
            )

            mock_labels.assert_called_once_with(
                stream_name="TAX_AGENT_EVENTS", consumer_group="tax-agent"
            )
            mock_histogram.observe.assert_called_once_with(150)

    def test_record_publish_with_default_error_type(self) -> None:
        """Test recording publish failure with default error type."""
        with patch.object(event_publish_errors_total, "labels") as mock_labels:
            mock_counter = MagicMock()
            mock_labels.return_value = mock_counter

            EventMetricsCollector.record_publish(
                topic="test.topic",
                duration_seconds=0.1,
                success=False,
                error_type=None,  # No error type provided
            )

            mock_labels.assert_called_once_with(
                topic="test.topic", error_type="unknown"  # Should default to "unknown"
            )
            mock_counter.inc.assert_called_once()

    def test_record_consume_with_default_error_type(self) -> None:
        """Test recording consume failure with default error type."""
        with patch.object(event_processing_errors_total, "labels") as mock_labels:
            mock_counter = MagicMock()
            mock_labels.return_value = mock_counter

            EventMetricsCollector.record_consume(
                topic="test.topic",
                consumer_group="test-group",
                duration_seconds=1.0,
                success=False,
                error_type=None,  # No error type provided
            )

            mock_labels.assert_called_once_with(
                topic="test.topic",
                consumer_group="test-group",
                error_type="unknown",  # Should default to "unknown"
            )
            mock_counter.inc.assert_called_once()
