# Unit tests for VendorBridge integration class.
# Tests polling mechanism, JSON conversion, delta-to-cumulative tracking, and error handling.

import json
import threading
import time
import sys
from pathlib import Path
from typing import Any, Dict
from unittest.mock import MagicMock, Mock, patch

import pytest

# Add the example directory to the path to allow importing the bridge
example_dir = Path(__file__).resolve().parent.parent.parent / "sdk-examples" / "vendor-bridge"
sys.path.insert(0, str(example_dir))

from api_to_otlp_bridge import MockVendorBridge
from mca_sdk.config import MCAConfig

# Mock response for requests.get
mock_api_response = {
    "model_id": "vendor-model-123",
    "metrics": {
        "predictions_since_last_poll": 10,
        "errors_since_last_poll": 1,
        "accuracy": 0.91,
        "f1_score": 0.88,
        "avg_latency_ms": 75.0,
    },
    "timestamp": "2026-02-14T12:00:00Z",
}


@pytest.fixture
def mock_requests_get():
    """Fixture to mock requests.get for the vendor bridge."""
    with patch("requests.get") as mock_get:
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = mock_api_response
        mock_get.return_value = mock_response
        yield mock_get


@pytest.fixture
def mock_mca_client():
    """Fixture to mock the MCAClient."""
    with patch("mca_sdk.integrations.bridge.MCAClient") as mock_client_class:
        mock_client = MagicMock()
        mock_client_class.return_value = mock_client
        yield mock_client_class


class TestVendorBridgeInitialization:
    """Test VendorBridge initialization."""

    def test_initialization_with_required_params(self, mock_requests_get, mock_mca_client):
        """Test bridge initialization with required parameters."""
        config = MCAConfig(
            service_name="test-service",
            vendor_api_url="http://mock-vendor.com/api",
            collector_endpoint="http://localhost:4318",
            allow_insecure_collector=True,
        )
        bridge = MockVendorBridge(config)

        # Service name is set during initialization, not from initial API fetch
        assert bridge.service_name == "vendor-model"
        assert bridge.vendor_name == "mock-vendor"
        assert bridge.endpoint == "http://mock-vendor.com/api"
        assert bridge.poll_interval == 30.0  # default
        assert not bridge.is_running()

    def test_initialization_with_custom_poll_interval(self, mock_requests_get, mock_mca_client):
        """Test bridge initialization with custom poll interval."""
        config = MCAConfig(
            service_name="test-service",
            vendor_api_url="http://mock-vendor.com/api",
            collector_endpoint="http://localhost:4318",
            allow_insecure_collector=True,
            vendor_bridge_poll_interval=60.0,
        )
        bridge = MockVendorBridge(config)

        assert bridge.poll_interval == 60.0


class TestVendorBridgePolling:
    """Test VendorBridge polling mechanism."""

    def test_start_stop_polling(self, mock_requests_get, mock_mca_client):
        """Test starting and stopping the polling loop."""
        config = MCAConfig(
            service_name="test-service",
            vendor_api_url="http://mock-vendor.com/api",
            collector_endpoint="http://localhost:4318",
            allow_insecure_collector=True,
            vendor_bridge_poll_interval=0.1,
        )
        bridge = MockVendorBridge(config)

        assert not bridge.is_running()

        bridge.start()
        assert bridge.is_running()

        # Wait for at least one poll to complete using deterministic check
        max_wait = 2.0  # Maximum 2 seconds
        start_time = time.time()
        while mock_requests_get.call_count < 1 and (time.time() - start_time) < max_wait:
            time.sleep(0.05)

        bridge.stop()
        assert not bridge.is_running()

        # Verify at least one poll occurred
        assert mock_requests_get.call_count >= 1

    def test_multiple_start_calls_no_op(self, mock_requests_get, mock_mca_client):
        """Test that calling start multiple times doesn't create multiple threads."""
        config = MCAConfig(
            service_name="test-service",
            vendor_api_url="http://mock-vendor.com/api",
            collector_endpoint="http://localhost:4318",
            allow_insecure_collector=True,
            vendor_bridge_poll_interval=1.0,
        )
        bridge = MockVendorBridge(config)

        bridge.start()
        thread1 = bridge._worker_thread

        bridge.start()  # Should be no-op
        thread2 = bridge._worker_thread

        assert thread1 is thread2  # Same thread

        bridge.stop()

    def test_stop_when_not_running_no_op(self, mock_requests_get, mock_mca_client):
        """Test that stopping when not running is a no-op."""
        config = MCAConfig(
            service_name="test-service",
            vendor_api_url="http://mock-vendor.com/api",
            collector_endpoint="http://localhost:4318",
            allow_insecure_collector=True,
        )
        bridge = MockVendorBridge(config)

        # Should not raise
        bridge.stop()
        bridge.stop()  # Multiple stops should be safe


class TestVendorBridgeHealthCheck:
    """Test VendorBridge health check functionality."""

    def test_health_check_success(self, mock_requests_get, mock_mca_client):
        """Test successful health check."""
        config = MCAConfig(
            service_name="test-service",
            vendor_api_url="http://mock-vendor.com/api",
            collector_endpoint="http://localhost:4318",
            allow_insecure_collector=True,
        )
        bridge = MockVendorBridge(config)
        bridge.start()
        assert bridge.health_check() is True
        bridge.stop()

    def test_health_check_failure(self, mock_requests_get, mock_mca_client):
        """Test failed health check."""
        config = MCAConfig(
            service_name="test-service",
            vendor_api_url="http://mock-vendor.com/api",
            collector_endpoint="http://localhost:4318",
            allow_insecure_collector=True,
        )
        bridge = MockVendorBridge(config)

        mock_requests_get.side_effect = ConnectionError("Cannot connect")

        assert bridge.health_check() is False
