"""
Plugin registry for managing discovered and loaded plugins.

This module provides a central registry for all plugins in the system.
"""

from typing import Dict, List, Optional, Type, Any
from .base import BasePlugin, PluginType


class PluginRegistry:
    """Central registry for managing plugins."""

    def __init__(self):
        """Initialize empty registry."""
        self._plugins: Dict[str, Type[BasePlugin]] = {}
        self._instances: Dict[str, BasePlugin] = {}
        self._plugins_by_type: Dict[PluginType, List[str]] = {}

    def register(self, plugin_class: Type[BasePlugin], name: Optional[str] = None) -> str:
        """
        Register a plugin class.

        Args:
            plugin_class: Plugin class to register
            name: Optional plugin name (uses class name if not provided)

        Returns:
            The name the plugin was registered under

        Raises:
            ValueError: If plugin name already exists
        """
        if name is None:
            name = plugin_class.__name__

        if name in self._plugins:
            raise ValueError(f"Plugin '{name}' is already registered")

        self._plugins[name] = plugin_class

        # Create instance to get metadata
        try:
            instance = plugin_class()
            plugin_type = instance.metadata.plugin_type

            if plugin_type not in self._plugins_by_type:
                self._plugins_by_type[plugin_type] = []

            self._plugins_by_type[plugin_type].append(name)
        except Exception:
            # If we can't get metadata, register as generic extension
            if PluginType.EXTENSION not in self._plugins_by_type:
                self._plugins_by_type[PluginType.EXTENSION] = []
            self._plugins_by_type[PluginType.EXTENSION].append(name)

        return name

    def unregister(self, name: str) -> bool:
        """
        Unregister a plugin.

        Args:
            name: Plugin name to unregister

        Returns:
            True if plugin was unregistered, False if not found
        """
        if name not in self._plugins:
            return False

        # Remove from instances if loaded
        if name in self._instances:
            instance = self._instances[name]
            instance.cleanup()
            del self._instances[name]

        # Remove from type mapping
        for plugin_type, plugin_names in self._plugins_by_type.items():
            if name in plugin_names:
                plugin_names.remove(name)
                break

        # Remove from main registry
        del self._plugins[name]
        return True

    def get_plugin(self, name: str, config: Dict[str, Any] = None) -> Optional[BasePlugin]:
        """
        Get plugin instance by name.

        Args:
            name: Plugin name
            config: Optional configuration for plugin

        Returns:
            Plugin instance or None if not found
        """
        if name not in self._plugins:
            return None

        # Return existing instance if already loaded and no new config
        if name in self._instances and config is None:
            return self._instances[name]

        # Create new instance
        try:
            plugin_class = self._plugins[name]
            instance = plugin_class(config)

            if instance.initialize():
                self._instances[name] = instance
                return instance
        except Exception:
            pass

        return None

    def get_plugins_by_type(self, plugin_type: PluginType) -> List[str]:
        """
        Get list of plugin names by type.

        Args:
            plugin_type: Type of plugins to retrieve

        Returns:
            List of plugin names of the specified type
        """
        return self._plugins_by_type.get(plugin_type, []).copy()

    def list_plugins(self) -> Dict[str, Dict[str, Any]]:
        """
        List all registered plugins with metadata.

        Returns:
            Dictionary mapping plugin names to metadata
        """
        result = {}

        for name, plugin_class in self._plugins.items():
            try:
                instance = plugin_class()
                metadata = instance.metadata
                result[name] = {
                    'name': metadata.name,
                    'version': metadata.version,
                    'description': metadata.description,
                    'author': metadata.author,
                    'type': metadata.plugin_type.value,
                    'dependencies': metadata.dependencies,
                    'markitect_version': metadata.markitect_version,
                    'loaded': name in self._instances
                }
            except Exception:
                result[name] = {
                    'name': name,
                    'error': 'Failed to load metadata'
                }

        return result

    def is_loaded(self, name: str) -> bool:
        """
        Check if plugin is loaded.

        Args:
            name: Plugin name

        Returns:
            True if plugin is loaded
        """
        return name in self._instances

    def reload_plugin(self, name: str, config: Dict[str, Any] = None) -> bool:
        """
        Reload a plugin with new configuration.

        Args:
            name: Plugin name
            config: New configuration

        Returns:
            True if reload successful
        """
        if name not in self._plugins:
            return False

        # Cleanup existing instance
        if name in self._instances:
            self._instances[name].cleanup()
            del self._instances[name]

        # Load with new config
        return self.get_plugin(name, config) is not None

    def cleanup_all(self) -> None:
        """Cleanup all loaded plugin instances."""
        for instance in self._instances.values():
            try:
                instance.cleanup()
            except Exception:
                pass
        self._instances.clear()


# Global plugin registry instance
plugin_registry = PluginRegistry()