import pytest
from pathlib import Path
import tempfile
import shutil
from multi_swarm.plugins.base import PluginBase, PluginMetadata
from multi_swarm.plugins.registry import PluginRegistry

class TestPlugin(PluginBase):
    """A test plugin for testing the registry."""
    def __init__(self):
        metadata = PluginMetadata(
            name="test_plugin",
            version="1.0.0",
            description="A test plugin",
            author="Test Author",
            requirements=["test-req"],
            dependencies=[],
            tags=["test"],
            config_schema={
                "type": "object",
                "properties": {
                    "test_setting": {"type": "string"}
                }
            }
        )
        super().__init__(metadata)
    
    def get_capabilities(self):
        return ["test_capability"]
    
    def health_check(self):
        return {
            "status": "healthy",
            "name": self.metadata.name,
            "version": self.metadata.version
        }

@pytest.fixture
def temp_plugin_dir():
    """Create a temporary directory for plugin discovery."""
    temp_dir = tempfile.mkdtemp()
    yield Path(temp_dir)
    shutil.rmtree(temp_dir)

@pytest.fixture
def plugin_registry():
    """Create a fresh plugin registry for each test."""
    registry = PluginRegistry()
    yield registry
    registry.cleanup_all()

class TestPluginRegistry:
    def test_registry_creation(self, plugin_registry):
        """Test plugin registry creation."""
        assert isinstance(plugin_registry._plugins, dict)
        assert isinstance(plugin_registry._instances, dict)
        assert isinstance(plugin_registry._plugin_paths, list)
    
    def test_plugin_registration(self, plugin_registry):
        """Test plugin registration."""
        # Register a plugin
        plugin_registry.register_plugin(TestPlugin)
        
        assert "test_plugin" in plugin_registry._plugins
        assert plugin_registry._plugins["test_plugin"] == TestPlugin
        
        # Test duplicate registration
        with pytest.raises(ValueError):
            plugin_registry.register_plugin(TestPlugin)
    
    def test_plugin_unregistration(self, plugin_registry):
        """Test plugin unregistration."""
        # Register and then unregister
        plugin_registry.register_plugin(TestPlugin)
        plugin_registry.unregister_plugin("test_plugin")
        
        assert "test_plugin" not in plugin_registry._plugins
        assert "test_plugin" not in plugin_registry._instances
    
    def test_plugin_instance_management(self, plugin_registry):
        """Test plugin instance management."""
        plugin_registry.register_plugin(TestPlugin)
        
        # Get instance
        instance = plugin_registry.get_plugin("test_plugin")
        assert isinstance(instance, TestPlugin)
        assert "test_plugin" in plugin_registry._instances
        
        # Get same instance again
        instance2 = plugin_registry.get_plugin("test_plugin")
        assert instance is instance2  # Should return same instance
    
    def test_plugin_discovery(self, temp_plugin_dir):
        """Test plugin discovery from paths."""
        # Create a new registry for this test
        registry = PluginRegistry()
        
        # Add discovery path
        registry.add_plugin_path(str(temp_plugin_dir))
        assert str(temp_plugin_dir) in registry._plugin_paths
        
        # Test discovery (mock plugin discovery by registering directly)
        registry.register_plugin(TestPlugin)
        
        discovered = registry.discover_plugins()
        assert len(discovered) > 0
        assert "test_plugin" in registry._plugins
    
    def test_plugin_filtering(self, plugin_registry):
        """Test plugin filtering by tags and capabilities."""
        plugin_registry.register_plugin(TestPlugin)
        
        # Test tag filtering
        plugins_by_tag = plugin_registry.get_plugins_by_tag("test")
        assert len(plugins_by_tag) == 1
        assert plugins_by_tag[0] == TestPlugin
        
        # Test capability filtering
        plugins_by_cap = plugin_registry.get_plugins_by_capability("test_capability")
        assert len(plugins_by_cap) == 1
        assert plugins_by_cap[0] == TestPlugin
    
    def test_health_check(self, plugin_registry):
        """Test health checking of plugins."""
        plugin_registry.register_plugin(TestPlugin)
        instance = plugin_registry.get_plugin("test_plugin")
        
        # Check individual plugin health
        health = instance.health_check()
        assert health["status"] == "healthy"
        
        # Check all plugins health
        all_health = plugin_registry.health_check_all()
        assert "test_plugin" in all_health
        assert all_health["test_plugin"]["status"] == "healthy"
    
    def test_cleanup(self, plugin_registry):
        """Test cleanup of plugin instances."""
        plugin_registry.register_plugin(TestPlugin)
        instance = plugin_registry.get_plugin("test_plugin")
        
        # Cleanup all plugins
        plugin_registry.cleanup_all()
        assert len(plugin_registry._instances) == 0
    
    def test_error_handling(self, plugin_registry):
        """Test error handling in plugin registry."""
        # Test getting non-existent plugin
        with pytest.raises(KeyError):
            plugin_registry.get_plugin("non_existent")
        
        # Test unregistering non-existent plugin
        with pytest.raises(KeyError):
            plugin_registry.unregister_plugin("non_existent")
        
        # Test invalid plugin path
        with pytest.raises(ValueError):
            plugin_registry.add_plugin_path("") 