"""
Integration tests for CAAE Service.

Tests the full API endpoints against experimental expectations.
"""

import pytest
from fastapi.testclient import TestClient

from caae.caae_service import app


class TestCAAEServiceAPI:
    """Test suite for CAAE Service REST API."""

    @pytest.fixture
    def client(self):
        """Create a test client for the FastAPI app."""
        return TestClient(app)

    # =========================================================================
    # Health Endpoint Tests
    # =========================================================================

    def test_health_endpoint(self, client):
        """Test: /v1/health returns healthy status."""
        response = client.get("/v1/health")

        assert response.status_code == 200
        data = response.json()
        assert data["status"] in ("healthy", "degraded")
        assert "version" in data
        assert "uptime_seconds" in data

    # =========================================================================
    # Metrics Endpoint Tests
    # =========================================================================

    def test_metrics_endpoint(self, client):
        """Test: /metrics returns valid metrics."""
        response = client.get("/metrics")

        assert response.status_code == 200
        data = response.json()
        assert "total_decisions" in data
        assert "swap_count" in data
        assert "recompute_count" in data
        assert "avg_decision_latency_ms" in data

    # =========================================================================
    # Decision Endpoint Tests
    # =========================================================================

    def test_decide_endpoint_basic(self, client):
        """Test: /v1/decide returns valid response."""
        response = client.post(
            "/v1/decide",
            json={
                "context_size_tokens": 25000,
                "bandwidth_gbps": 16.0,
                "pcie_queue_depth_ms": 0.5,
                "request_id": "test-basic",
            },
        )

        assert response.status_code == 200
        data = response.json()

        assert data["action"] in ("swap", "recompute", "hold")
        assert "predicted_swap_ms" in data
        assert "predicted_recompute_ms" in data
        assert "confidence" in data
        assert "circuit_breaker_active" in data

    def test_decide_gen4_25k_returns_swap(self, client):
        """
        Test: 25k tokens on Gen 4 should return SWAP action.

        From Experiment 5 Phase 4:
        - Swap cost: 10.1ms
        - Recompute cost: 122.7ms
        - Optimal action: SWAP
        """
        response = client.post(
            "/v1/decide",
            json={
                "context_size_tokens": 25000,
                "bandwidth_gbps": 16.0,
                "pcie_queue_depth_ms": 0.09,
                "request_id": "test-gen4-25k",
            },
        )

        assert response.status_code == 200
        data = response.json()

        assert data["action"] == "swap", f"Expected SWAP, got {data['action']}"

        # Validate cost estimates are in expected range
        assert (
            3.0 <= data["predicted_swap_ms"] <= 6.0
        ), f"Swap cost {data['predicted_swap_ms']} not in expected range"

    def test_decide_gen5_100k_returns_swap(self, client):
        """
        Test: 100k tokens on Gen 5 should return SWAP action.

        From Experiment 6:
        - Swap cost: ~1.3ms
        - Recompute cost: ~568.4ms
        - Optimal action: SWAP
        """
        response = client.post(
            "/v1/decide",
            json={
                "context_size_tokens": 100000,
                "bandwidth_gbps": 128.0,
                "pcie_queue_depth_ms": 0.1,
                "request_id": "test-gen5-100k",
            },
        )

        assert response.status_code == 200
        data = response.json()

        assert data["action"] == "swap"
        assert (
            data["predicted_swap_ms"] < 5.0
        ), f"Swap cost should be < 5ms, got {data['predicted_swap_ms']}"
        assert data["confidence"] > 0.95

    def test_decide_circuit_breaker_activation(self, client):
        """
        Test: Circuit breaker activates when queue depth > threshold.
        """
        response = client.post(
            "/v1/decide",
            json={
                "context_size_tokens": 25000,
                "bandwidth_gbps": 16.0,
                "pcie_queue_depth_ms": 10.0,  # High queue depth
                "circuit_breaker_threshold_ms": 5.0,
                "request_id": "test-cb",
            },
        )

        assert response.status_code == 200
        data = response.json()

        # After enough high queue depth checks, circuit breaker may activate
        # The actual behavior depends on circuit breaker state
        assert "circuit_breaker_active" in data

    def test_decide_confidence_above_95_percent(self, client):
        """
        Test: Decision confidence should be >= 95% (from Experiment 2).
        """
        response = client.post(
            "/v1/decide",
            json={
                "context_size_tokens": 25000,
                "bandwidth_gbps": 16.0,
                "pcie_queue_depth_ms": 0.5,
                "request_id": "test-confidence",
            },
        )

        assert response.status_code == 200
        data = response.json()

        assert (
            data["confidence"] >= 0.95
        ), f"Expected confidence >= 95%, got {data['confidence']:.1%}"

    def test_decide_includes_reasoning(self, client):
        """Test: Response includes human-readable reasoning."""
        response = client.post(
            "/v1/decide",
            json={
                "context_size_tokens": 25000,
                "bandwidth_gbps": 16.0,
                "request_id": "test-reasoning",
            },
        )

        assert response.status_code == 200
        data = response.json()

        assert "reasoning" in data
        assert len(data["reasoning"]) > 0

    # =========================================================================
    # Validation Tests
    # =========================================================================

    def test_decide_rejects_invalid_tokens(self, client):
        """Test: Reject request with non-positive token count."""
        response = client.post(
            "/v1/decide",
            json={"context_size_tokens": 0, "bandwidth_gbps": 16.0},  # Invalid
        )

        assert response.status_code == 422  # Validation error

    def test_decide_rejects_invalid_bandwidth(self, client):
        """Test: Reject request with non-positive bandwidth."""
        response = client.post(
            "/v1/decide",
            json={"context_size_tokens": 25000, "bandwidth_gbps": 0},  # Invalid
        )

        assert response.status_code == 422  # Validation error

    # =========================================================================
    # Latency Tests
    # =========================================================================

    def test_decide_latency_under_1ms(self, client):
        """
        Test: Decision latency should be < 1ms.

        From Experiment 1A: Overhead should be < 0.5ms
        """
        import time

        start = time.perf_counter()
        response = client.post(
            "/v1/decide", json={"context_size_tokens": 25000, "bandwidth_gbps": 16.0}
        )
        latency_ms = (time.perf_counter() - start) * 1000

        assert response.status_code == 200

        # Allow generous tolerance for test environment overhead
        # In production, this should be < 1ms
        assert (
            latency_ms < 50
        ), f"Decision took {latency_ms:.2f}ms, expected < 50ms in test"


class TestCAAEServiceRoot:
    """Tests for root endpoint."""

    @pytest.fixture
    def client(self):
        return TestClient(app)

    def test_root_returns_service_info(self, client):
        """Test: Root endpoint returns service information."""
        response = client.get("/")

        assert response.status_code == 200
        data = response.json()

        assert data["service"] == "CAAE Advisor"
        assert "version" in data
        assert "endpoints" in data
        assert "documentation" in data


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
