"""Tests for buffering integration in MCAClient.

Tests the integration of TelemetryQueue with MCAClient for buffering
telemetry when the collector is unreachable.
"""

import time
import pytest
from mca_sdk import MCAClient


class TestBufferingIntegration:
    """Test buffering integration with MCAClient."""

    def test_client_without_buffering(self):
        """Test MCAClient works without buffering enabled (default)."""
        client = MCAClient(
            service_name="test-service", model_id="test-model", team_name="test-team"
        )

        # Buffering should be disabled by default
        assert client.buffer_stats() is None

        client.shutdown()

    def test_client_with_buffering_enabled(self):
        """Test MCAClient initializes with buffering enabled."""
        client = MCAClient(
            service_name="test-service",
            model_id="test-model",
            team_name="test-team",
            buffering_enabled=True,
            max_queue_size=100,
        )

        # Buffering should be enabled with aggregated stats
        stats = client.buffer_stats()
        assert stats is not None
        assert stats["enabled"] is True
        assert "per_signal_stats" in stats
        assert "total_queued_items" in stats

        client.shutdown()

    def test_buffer_stats_method(self):
        """Test buffer_stats() method returns correct statistics."""
        client = MCAClient(
            service_name="test-service",
            model_id="test-model",
            team_name="test-team",
            buffering_enabled=True,
            max_queue_size=50,
        )

        stats = client.buffer_stats()
        assert "enabled" in stats
        assert stats["enabled"] is True
        assert "per_signal_stats" in stats
        assert "total_export_attempts" in stats

        client.shutdown()

    def test_buffer_stats_returns_none_when_disabled(self):
        """Test buffer_stats() returns None when buffering is disabled."""
        client = MCAClient(
            service_name="test-service",
            model_id="test-model",
            team_name="test-team",
            # buffering_enabled not set (defaults to False)
        )

        stats = client.buffer_stats()
        assert stats is None

        client.shutdown()

    def test_client_with_buffering_and_persistence(self, caplog):
        """Test queue persistence generates HIPAA compliance warnings (Finding 1)."""
        import tempfile
        import os
        import warnings

        with tempfile.TemporaryDirectory() as tmpdir:
            persist_path = os.path.join(tmpdir, "queue.pkl")

            # Verify that enabling persistence generates SecurityWarning (not error)
            with warnings.catch_warnings(record=True) as w:
                warnings.simplefilter("always")
                client = MCAClient(
                    service_name="test-service",
                    model_id="test-model",
                    team_name="test-team",
                    buffering_enabled=True,
                    max_queue_size=100,
                    persist_queue=True,
                    persist_path=persist_path,
                )

                # Verify SecurityWarning was raised about unencrypted persistence
                security_warnings = [
                    warning for warning in w if "Queue persistence" in str(warning.message)
                ]
                assert len(security_warnings) > 0, "Should warn about unencrypted queue persistence"
                assert "PHI" in str(security_warnings[0].message), "Warning should mention PHI"

                client.shutdown()

    def test_shutdown_logs_buffer_statistics(self):
        """Test shutdown logs buffer statistics when buffering enabled."""
        client = MCAClient(
            service_name="test-service",
            model_id="test-model",
            team_name="test-team",
            buffering_enabled=True,
            max_queue_size=100,
        )

        # Should not raise exception during shutdown
        client.shutdown()

    def test_buffering_with_small_queue_size(self):
        """Test buffering with very small queue size."""
        client = MCAClient(
            service_name="test-service",
            model_id="test-model",
            team_name="test-team",
            buffering_enabled=True,
            max_queue_size=5,
        )

        stats = client.buffer_stats()
        assert stats["enabled"] is True

        client.shutdown()

    def test_buffering_with_large_queue_size(self):
        """Test buffering with large queue size."""
        client = MCAClient(
            service_name="test-service",
            model_id="test-model",
            team_name="test-team",
            buffering_enabled=True,
            max_queue_size=10000,
        )

        stats = client.buffer_stats()
        assert stats["enabled"] is True

        client.shutdown()

    def test_collector_unavailable_queues_telemetry(self):
        """Test telemetry is queued when collector is unreachable (AC#1)."""
        # Use invalid localhost endpoint to simulate collector unavailable
        client = MCAClient(
            service_name="test-service",
            model_id="test-model",
            team_name="test-team",
            buffering_enabled=True,
            max_queue_size=100,
            metric_export_interval_ms=1000,  # 1 second for faster testing
            collector_endpoint="http://localhost:9999",  # Non-existent port
        )

        # Capture baseline stats
        stats_before = client.buffer_stats()
        assert stats_before is not None
        assert stats_before["enabled"] is True
        baseline_queued = stats_before["per_signal_stats"]["metrics"]["items_queued"]
        baseline_failures = stats_before["total_export_failures"]

        # Record prediction (should fail to export and queue instead)
        client.record_prediction(
            input_data={"feature": "value"}, output={"prediction": 0.95}, latency=0.15
        )

        # Wait for periodic export to trigger (1s interval + retry delays with exponential backoff)
        # Retry delays: 1s + 2s + 4s = 7s total, plus 1s for export interval = 8s minimum
        time.sleep(10)

        # Verify queueing occurred
        stats_after = client.buffer_stats()
        assert (
            stats_after["total_export_failures"] > baseline_failures
        ), "Export should have failed when collector unavailable"
        assert (
            stats_after["per_signal_stats"]["metrics"]["items_queued"] > baseline_queued
        ), "Failed metrics should have been queued for retry"

        client.shutdown()

    def test_queue_flush_on_shutdown(self):
        """Test buffered telemetry is flushed on shutdown (AC#3).

        Tests that shutdown triggers export attempts even when collector is unavailable.
        With buffering enabled, telemetry should be recorded and export attempted during shutdown.
        """
        # Create client with buffering (persistence intentionally disabled)
        # Disable circuit breaker to prevent it from interfering with queue state
        client = MCAClient(
            service_name="test-service",
            model_id="test-model",
            team_name="test-team",
            buffering_enabled=True,
            max_queue_size=100,
            metric_export_interval_ms=60000,  # 60 seconds - very long to ensure no automatic export
            collector_endpoint="http://localhost:9999",  # Invalid port but valid localhost
            circuit_breaker_enabled=False,  # Disable to test pure queue behavior
        )

        # Record prediction (will be buffered, not immediately exported due to long interval)
        client.record_prediction(input_data={"test": 1}, output={"result": 0})

        # Wait briefly to ensure prediction is recorded
        time.sleep(0.5)

        # Get baseline stats (should show no exports yet due to long interval)
        stats_before = client.buffer_stats()
        assert stats_before["enabled"] is True
        export_attempts_before = stats_before["total_export_attempts"]

        # Shutdown should trigger flush attempt
        client.shutdown()

        # Get stats after shutdown
        stats_after = client.buffer_stats()
        assert stats_after is not None, "Stats should be available after shutdown"

        # Verify that shutdown triggered export attempts
        # Export will fail (invalid endpoint) but attempts should increase
        export_attempts_after = stats_after["total_export_attempts"]
        assert (
            export_attempts_after > export_attempts_before
        ), f"Shutdown should trigger export flush (before: {export_attempts_before}, after: {export_attempts_after})"

    def test_batch_export_respects_batch_size(self):
        """Test batch export respects batch_size limits (AC#4)."""
        client = MCAClient(
            service_name="test-service",
            model_id="test-model",
            team_name="test-team",
            buffering_enabled=True,
            max_queue_size=500,
            collector_endpoint="http://localhost:4318",  # Assume collector running
        )

        # Record multiple predictions
        for i in range(150):
            client.record_prediction(input_data={"id": i}, output={"result": i}, latency=0.1)

        # Force flush
        client._meter_provider.force_flush(timeout_millis=5000)

        # Verify batching occurred
        stats = client.buffer_stats()
        export_attempts = stats["per_signal_stats"]["metrics"]["export_attempts"]

        assert export_attempts >= 1, "Should have attempted at least one export"
        assert export_attempts <= 150, "Should not export each prediction individually"
        assert (
            stats["per_signal_stats"]["metrics"]["queue_size"] == 0
        ), "Queue should be empty with successful exports"

        client.shutdown()

    def test_buffering_end_to_end_with_prediction(self):
        """Test buffering works with actual prediction recording (NOT SKIPPED).

        Verifies MCAClient + TelemetryQueue integration end-to-end.
        """
        client = MCAClient(
            service_name="e2e-test",
            model_id="test-model",
            team_name="test-team",
            buffering_enabled=True,
            max_queue_size=100,
        )

        # Verify buffering is enabled
        initial_stats = client.buffer_stats()
        assert initial_stats["enabled"] is True

        # Record prediction (tests full integration)
        client.record_prediction(input_data={"feature": 1.0}, output={"pred": 0.85}, latency=0.123)

        # Verify buffering still enabled
        final_stats = client.buffer_stats()
        assert final_stats["enabled"] is True

        client.shutdown()
        # If telemetry exported successfully, queue is empty and file may not persist
        # Test verifies integration works, not file existence
