"""Simplified LLMEngine Contract Tests.

Fast contract tests for LLMEngine interface verification.
These tests do NOT require model loading (no @pytest.mark.slow).

For full contract tests with model loading, see test_llm_engine_contract.py.

Note: BaseEngine and EngineFactory have been removed (issue #24).
      LLMEngine is now the unified hardware-agnostic engine.
"""

from __future__ import annotations

import pytest

from sagellm_core import LLMEngine, LLMEngineConfig
from sagellm_core.health import HealthStatus
from sagellm_protocol import CapabilityDescriptor


class TestLLMEngineContract:
    """Test LLMEngine interface contract (no model loading required)."""

    def test_interface_has_required_methods(self) -> None:
        """Verify LLMEngine has all required methods."""
        required_methods = [
            # Core lifecycle
            "start",
            "stop",
            "health_check",
            # Inference
            "execute",
            "stream",
            "generate",
            # Task2 interfaces (issue #8)
            "capabilities",
            "get_kv_cache",
            "set_scheduler",
        ]

        for method in required_methods:
            assert hasattr(LLMEngine, method), f"LLMEngine missing method: {method}"

    def test_interface_has_required_properties(self) -> None:
        """Verify LLMEngine has all required properties."""
        required_properties = [
            "engine_id",
            "config",
            "is_running",
            "backend",
        ]

        for prop in required_properties:
            assert hasattr(LLMEngine, prop), f"LLMEngine missing property: {prop}"

    def test_config_validation_model_path_required(self) -> None:
        """LLMEngineConfig must require model_path."""
        with pytest.raises(ValueError, match="model_path"):
            LLMEngineConfig(model_path="")

    def test_config_validation_backend_type(self) -> None:
        """LLMEngine must validate backend_type."""
        config = LLMEngineConfig(model_path="test", backend_type="invalid_backend")
        with pytest.raises(ValueError, match="Unknown backend"):
            LLMEngine(config)

    def test_valid_backend_types_accepted(self) -> None:
        """LLMEngine must accept valid backend types."""
        valid_backends = ["cpu", "cuda", "ascend", "auto"]
        for backend in valid_backends:
            config = LLMEngineConfig(model_path="test", backend_type=backend)
            engine = LLMEngine(config)
            assert engine is not None
            assert not engine.is_running  # Not started yet


class TestHealthStatus:
    """Test HealthStatus enum."""

    def test_health_status_values(self) -> None:
        """Verify HealthStatus has correct values."""
        from enum import Enum

        assert issubclass(HealthStatus, Enum)

        required_values = ["HEALTHY", "DEGRADED", "UNHEALTHY"]
        actual_values = [e.name for e in HealthStatus]

        for value in required_values:
            assert value in actual_values, f"HealthStatus missing value: {value}"


class TestTask2InterfaceContract:
    """Test Task2 interface contract (issue #8)."""

    def test_capabilities_returns_capability_descriptor(self) -> None:
        """capabilities() must return CapabilityDescriptor."""
        config = LLMEngineConfig(model_path="test", backend_type="cpu")
        engine = LLMEngine(config)

        # Before start, should return unknown device_type
        cap = engine.capabilities()
        assert isinstance(cap, CapabilityDescriptor)
        assert cap.device_type == "unknown"

    def test_get_kv_cache_returns_none_initially(self) -> None:
        """get_kv_cache() must return None when not initialized."""
        config = LLMEngineConfig(model_path="test", backend_type="cpu")
        engine = LLMEngine(config)

        kv_cache = engine.get_kv_cache()
        assert kv_cache is None

    def test_set_scheduler_accepts_scheduler(self) -> None:
        """set_scheduler() must accept scheduler instance."""
        config = LLMEngineConfig(model_path="test", backend_type="cpu")
        engine = LLMEngine(config)

        class MockScheduler:
            pass

        scheduler = MockScheduler()
        # Should not raise
        engine.set_scheduler(scheduler)
        assert engine._scheduler is scheduler
