"""
Tests for the GateWay Prometheus Metrics System

Tests cover:
- Metrics initialization and configuration
- HTTP request tracking
- Job lifecycle metrics
- Resource utilization tracking
- Billing metrics
- Queue metrics
- Provider metrics
- Checkpoint metrics
- WebSocket metrics
- Scheduler metrics
- Middleware functionality
- Metrics endpoint output
"""

import asyncio
import time
from unittest.mock import Mock

import pytest


class TestMetricsImport:
    """Test metrics module can be imported."""

    def test_import_module(self):
        """Test that the metrics module can be imported."""
        from verlex_server.gateway.backend.metrics import (
            MetricsConfig,
            MetricsManager,
        )

        # Basic assertions
        assert MetricsConfig is not None
        assert MetricsManager is not None

    def test_prometheus_availability(self):
        """Test Prometheus client availability check."""
        from verlex_server.gateway.backend.metrics import PROMETHEUS_AVAILABLE
        # Should be a boolean
        assert isinstance(PROMETHEUS_AVAILABLE, bool)


class TestMetricsConfig:
    """Tests for MetricsConfig."""

    def test_default_config(self):
        """Test default configuration values."""
        from verlex_server.gateway.backend.metrics import MetricsConfig

        config = MetricsConfig()

        assert config.enabled is True
        assert config.endpoint == "/metrics"
        assert config.service_name == "gateway"
        assert config.multiprocess_mode is False

    def test_custom_config(self):
        """Test custom configuration."""
        from verlex_server.gateway.backend.metrics import MetricsConfig

        config = MetricsConfig(
            enabled=False,
            endpoint="/custom-metrics",
            service_name="custom-gateway",
        )

        assert config.enabled is False
        assert config.endpoint == "/custom-metrics"
        assert config.service_name == "custom-gateway"

    def test_histogram_buckets(self):
        """Test histogram bucket configuration."""
        from verlex_server.gateway.backend.metrics import MetricsConfig

        config = MetricsConfig()

        # Request latency buckets should cover common API latencies
        assert config.request_latency_buckets[0] < 0.01  # Fast responses
        assert config.request_latency_buckets[-1] >= 10.0  # Slow responses

        # Job duration buckets should cover long-running jobs
        assert config.job_duration_buckets[-1] >= 3600  # Up to 1+ hours


class TestMetricsManager:
    """Tests for MetricsManager singleton."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_singleton_pattern(self):
        """Test MetricsManager is a singleton."""
        from verlex_server.gateway.backend.metrics import MetricsManager

        manager1 = MetricsManager()
        manager2 = MetricsManager()

        assert manager1 is manager2

    def test_get_metrics_manager(self):
        """Test get_metrics_manager helper."""
        from verlex_server.gateway.backend.metrics import MetricsManager, get_metrics_manager
        MetricsManager._reset()

        manager = get_metrics_manager()

        assert manager is not None
        assert isinstance(manager, MetricsManager)

    def test_configure_metrics(self):
        """Test configure_metrics creates manager with config."""
        from verlex_server.gateway.backend.metrics import (
            MetricsConfig,
            MetricsManager,
            configure_metrics,
        )
        MetricsManager._reset()

        config = MetricsConfig(service_name="test-service")
        manager = configure_metrics(config)

        assert manager.config.service_name == "test-service"


class TestHTTPMetricsTracking:
    """Tests for HTTP request metrics tracking."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_track_request_start(self):
        """Test tracking request start."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        # Should not raise
        manager.track_request_start("GET", "/v1/jobs")

    def test_track_request_end(self):
        """Test tracking request end."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        # Should not raise
        manager.track_request_end(
            method="GET",
            endpoint="/v1/jobs",
            status_code=200,
            duration_seconds=0.05,
            request_size=100,
            response_size=1024,
        )

    def test_track_request_context_manager(self):
        """Test track_request context manager."""
        from verlex_server.gateway.backend.metrics import track_request

        with track_request("POST", "/v1/jobs/submit") as tracker:
            # Simulate work
            time.sleep(0.01)
            tracker.set_status(201)

        # Should complete without error

    def test_track_request_with_error(self):
        """Test track_request records 500 on exception."""
        from verlex_server.gateway.backend.metrics import track_request

        with pytest.raises(ValueError):
            with track_request("POST", "/v1/jobs/submit"):
                raise ValueError("Test error")


class TestJobMetricsTracking:
    """Tests for job lifecycle metrics tracking."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_track_job_submitted(self):
        """Test tracking job submission."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_job_submitted(mode="P", provider="gcp")
        # Should not raise

    def test_track_job_completed(self):
        """Test tracking job completion."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_job_completed(
            mode="P",
            provider="gcp",
            status="completed",
            duration_seconds=120.5,
            instance_type="n1-standard-4",
            queue_wait_seconds=5.0,
            pricing_tier="priority",
        )
        # Should not raise

    def test_track_job_helper_function(self):
        """Test track_job helper function."""
        from verlex_server.gateway.backend.metrics import track_job

        track_job(
            job_id="job_abc123",
            status="completed",
            duration_seconds=60.0,
            mode="P",
            provider="gcp",
            instance_type="n1-standard-4",
            queue_wait_seconds=2.5,
            pricing_tier="priority",
            revenue=1.50,
            cost=1.20,
        )
        # Should not raise

    def test_track_job_in_progress(self):
        """Test tracking jobs in progress."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        # Increment
        manager.track_job_in_progress("gcp", "us-central1", delta=1)

        # Decrement
        manager.track_job_in_progress("gcp", "us-central1", delta=-1)

    def test_set_jobs_queued(self):
        """Test setting queued job count."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.set_jobs_queued("priority", 5)
        manager.set_jobs_queued("patient", 10)

    def test_track_job_retry(self):
        """Test tracking job retries."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_job_retry(reason="timeout")
        manager.track_job_retry(reason="oom")


class TestResourceMetricsTracking:
    """Tests for resource utilization metrics."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_track_gpu_usage(self):
        """Test tracking GPU hours."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_gpu_usage(
            hours=2.5,
            gpu_type="A100",
            provider="gcp",
            region="us-central1",
        )

    def test_track_cpu_usage(self):
        """Test tracking CPU seconds."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_cpu_usage(
            seconds=3600,
            provider="gcp",
            region="us-central1",
        )

    def test_track_memory_usage(self):
        """Test tracking memory GB-seconds."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_memory_usage(
            gb_seconds=14400,  # 4GB for 1 hour
            provider="gcp",
            region="us-central1",
        )

    def test_set_instance_utilization(self):
        """Test setting instance utilization."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.set_instance_utilization(
            utilization=0.75,
            provider="gcp",
            region="us-central1",
            instance_type="n1-standard-4",
        )

    def test_set_active_instances(self):
        """Test setting active instance count."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.set_active_instances(
            count=10,
            provider="gcp",
            region="us-central1",
            instance_type="n1-standard-4",
        )


class TestBillingMetricsTracking:
    """Tests for billing metrics."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_track_revenue(self):
        """Test tracking revenue."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_revenue(dollars=10.50, mode="P", provider="gcp")

    def test_track_provider_cost(self):
        """Test tracking provider cost."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_provider_cost(dollars=8.40, provider="gcp", region="us-central1")

    def test_track_margin(self):
        """Test tracking margin."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_margin(dollars=2.10, mode="P")

    def test_track_credits(self):
        """Test tracking credits."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_credits_used(amount=50.0, tier="pro")
        manager.track_credits_purchased(amount=100.0, payment_method="stripe")


class TestQueueMetrics:
    """Tests for queue metrics."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_set_queue_depth(self):
        """Test setting queue depth."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.set_queue_depth(queue_name="priority", priority="high", depth=15)

    def test_set_queue_oldest_message(self):
        """Test setting oldest message age."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.set_queue_oldest_message(queue_name="patient", age_seconds=300)

    def test_track_queue_message_processed(self):
        """Test tracking processed messages."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_queue_message_processed(queue_name="priority", status="success")


class TestProviderMetrics:
    """Tests for cloud provider metrics."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_set_provider_availability(self):
        """Test setting provider availability."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.set_provider_availability("gcp", "us-central1", available=True)
        manager.set_provider_availability("aws", "us-east-1", available=False)

    def test_track_provider_api_latency(self):
        """Test tracking provider API latency."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_provider_api_latency(
            seconds=0.25,
            provider="gcp",
            operation="create_instance",
        )

    def test_track_provider_error(self):
        """Test tracking provider errors."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_provider_error(provider="gcp", error_type="RateLimitError")

    def test_track_spot_preemption(self):
        """Test tracking spot preemptions."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_spot_preemption(provider="gcp", region="us-central1")


class TestCheckpointMetrics:
    """Tests for checkpoint metrics."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_track_checkpoint_saved(self):
        """Test tracking checkpoint saves."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_checkpoint_saved(
            provider="minio",
            size_bytes=1048576,  # 1MB
            duration_seconds=0.5,
        )


class TestWebSocketMetrics:
    """Tests for WebSocket metrics."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_track_websocket_connect_disconnect(self):
        """Test tracking WebSocket connections."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_websocket_connect(connection_type="output_stream")
        manager.track_websocket_disconnect(connection_type="output_stream")

    def test_track_websocket_message(self):
        """Test tracking WebSocket messages."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_websocket_message(direction="inbound", message_type="subscribe")
        manager.track_websocket_message(direction="outbound", message_type="output")


class TestSchedulerMetrics:
    """Tests for scheduler metrics."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_track_scheduler_poll(self):
        """Test tracking scheduler polls."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_scheduler_poll()

    def test_track_job_dispatched(self):
        """Test tracking job dispatch."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_job_dispatched(worker_id="worker-1")

    def test_set_scheduler_status(self):
        """Test setting scheduler status."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.set_scheduler_status(instance_id="scheduler-1", running=True)
        manager.set_scheduler_status(instance_id="scheduler-1", running=False)

    def test_set_worker_pool_metrics(self):
        """Test setting worker pool metrics."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.set_worker_pool_size(pool_id="main", size=10)
        manager.set_worker_pool_utilization(pool_id="main", utilization=0.8)


class TestUserAuthMetrics:
    """Tests for user and authentication metrics."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_set_active_users(self):
        """Test setting active user count."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.set_active_users(count=100, tier="free")
        manager.set_active_users(count=50, tier="pro")

    def test_set_api_keys_active(self):
        """Test setting active API key count."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.set_api_keys_active(count=250)

    def test_track_auth_attempt(self):
        """Test tracking auth attempts."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        manager.track_auth_attempt(method="api_key", status="success")
        manager.track_auth_attempt(method="jwt", status="failure")


class TestMetricsOutput:
    """Tests for metrics output generation."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_generate_metrics(self):
        """Test metrics output generation."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        output = manager.generate_metrics()

        assert isinstance(output, bytes)

    def test_get_content_type(self):
        """Test metrics content type."""
        from verlex_server.gateway.backend.metrics import get_metrics_manager

        manager = get_metrics_manager()

        content_type = manager.get_content_type()

        assert isinstance(content_type, str)
        assert "text" in content_type or "prometheus" in content_type.lower()


class TestMetricsMiddleware:
    """Tests for FastAPI metrics middleware."""

    def test_middleware_init(self):
        """Test middleware initialization."""
        from verlex_server.gateway.backend.metrics import MetricsMiddleware

        mock_app = Mock()
        middleware = MetricsMiddleware(mock_app)

        assert middleware.app is mock_app
        assert "/metrics" in middleware.excluded_paths
        assert "/health" in middleware.excluded_paths

    def test_normalize_endpoint(self):
        """Test endpoint normalization."""
        from verlex_server.gateway.backend.metrics import MetricsMiddleware

        mock_app = Mock()
        middleware = MetricsMiddleware(mock_app)

        # Test job ID normalization
        normalized = middleware._normalize_endpoint("/v1/jobs/job_abc123/result")
        assert "{job_id}" in normalized

        # Test UUID normalization
        normalized = middleware._normalize_endpoint("/v1/users/12345678-1234-1234-1234-123456789012")
        assert "{id}" in normalized


class TestTrackingDecorators:
    """Tests for tracking decorators."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    @pytest.mark.asyncio
    async def test_track_execution_decorator(self):
        """Test async tracking decorator."""
        from verlex_server.gateway.backend.metrics import track_execution

        @track_execution(operation="test_op", provider="test")
        async def async_function():
            await asyncio.sleep(0.01)
            return "result"

        result = await async_function()
        assert result == "result"

    @pytest.mark.asyncio
    async def test_track_execution_with_error(self):
        """Test async tracking decorator with error."""
        from verlex_server.gateway.backend.metrics import track_execution

        @track_execution(operation="test_op", provider="test")
        async def async_function():
            raise ValueError("Test error")

        with pytest.raises(ValueError):
            await async_function()

    def test_track_sync_execution_decorator(self):
        """Test sync tracking decorator."""
        from verlex_server.gateway.backend.metrics import track_sync_execution

        @track_sync_execution(operation="test_op", provider="test")
        def sync_function():
            return "result"

        result = sync_function()
        assert result == "result"


class TestMetricsRouter:
    """Tests for FastAPI metrics router."""

    def test_create_metrics_router(self):
        """Test metrics router creation."""
        from verlex_server.gateway.backend.metrics import create_metrics_router

        router = create_metrics_router()

        assert router is not None
        # Router should have a /metrics route
        routes = [r.path for r in router.routes]
        assert "/metrics" in routes


class TestMetricsDisabled:
    """Tests for behavior when metrics are disabled."""

    def setup_method(self):
        """Reset singleton before each test."""
        from verlex_server.gateway.backend.metrics import MetricsManager
        MetricsManager._reset()

    def test_metrics_manager_without_prometheus(self):
        """Test MetricsManager works without prometheus_client."""
        from verlex_server.gateway.backend.metrics import MetricsConfig, MetricsManager

        config = MetricsConfig(enabled=False)
        manager = MetricsManager(config)

        # All tracking methods should work without errors
        manager.track_job_submitted(mode="P", provider="gcp")
        manager.track_job_completed(
            mode="P", provider="gcp", status="completed",
            duration_seconds=60.0
        )

        # Output should still be valid
        output = manager.generate_metrics()
        assert isinstance(output, bytes)
