"""Unified plugin registry for managing multiple domain-specific plugin systems with configuration persistence"""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/core/registry.ipynb.

# %% auto 0
__all__ = ['T', 'PluginMetadata', 'UnifiedPluginRegistry']

# %% ../../nbs/core/registry.ipynb 3
import json
from dataclasses import dataclass, field
from pathlib import Path
from typing import Dict, List, Optional, Any, TypeVar, Type

from cjm_fasthtml_jsonschema.core.dataclass import dataclass_to_jsonschema

# %% ../../nbs/core/registry.ipynb 5
@dataclass
class PluginMetadata:
    """Metadata describing a plugin for display and configuration management."""
    name: str  # Internal plugin identifier
    category: str  # Plugin category string (application-defined)
    title: str  # Display title for the plugin
    config_schema: Dict[str, Any]  # JSON Schema for plugin configuration
    config_dataclass: Optional[Type] = None  # Configuration dataclass type (if available)
    description: Optional[str] = None  # Plugin description
    version: Optional[str] = None  # Plugin version
    is_configured: bool = False  # Whether the plugin has saved configuration
    
    def get_unique_id(self) -> str:  # String in format 'category_name'
        """Generate unique ID for this plugin."""
        return f"{self.category}_{self.name}"

# %% ../../nbs/core/registry.ipynb 7
T = TypeVar('T')

class UnifiedPluginRegistry:
    """Unified registry for multiple domain-specific plugin systems with configuration persistence."""
    
    def __init__(self, 
                 config_dir: Optional[Path] = None  # Directory for plugin configuration files (default: 'configs')
                ):
        """Initialize the unified plugin registry."""
        self._managers: Dict[str, Any] = {}  # category -> manager
        self._categories: Dict[str, str] = {}  # category -> display_name
        self._plugins: Dict[str, PluginMetadata] = {}  # unique_id -> metadata
        self._config_dir = config_dir or Path("configs")
        self._config_dir.mkdir(exist_ok=True, parents=True)
    
    def register_plugin_manager(
        self,
        category: str,  # Category name (e.g., "transcription", "llm")
        manager: Any,  # Domain-specific plugin manager
        display_name: Optional[str] = None,  # Display name for UI
        auto_discover: bool = True  # Automatically discover plugins?
    ) -> List[PluginMetadata]:  # List of discovered plugin metadata
        """Register a domain-specific plugin manager."""
        self._managers[category] = manager
        self._categories[category] = display_name or category.title()
        
        if auto_discover:
            return self._discover_and_register_plugins(category, manager)
        return []
    
    def register_plugin_system(
        self,
        category: str,  # Category name (e.g., "transcription", "llm")
        plugin_interface: Type,  # Plugin interface class (e.g., TranscriptionPlugin)
        display_name: Optional[str] = None,  # Display name for UI
        auto_discover: bool = True  # Automatically discover plugins?
    ) -> List[PluginMetadata]:  # List of discovered plugin metadata
        """
        Create and register a plugin system in one step. This is a convenience method that creates a PluginManager with the
        specified interface and registers it with the registry.
        """
        from cjm_plugin_system.core.manager import PluginManager
        
        manager = PluginManager(plugin_interface=plugin_interface)
        return self.register_plugin_manager(
            category=category,
            manager=manager,
            display_name=display_name,
            auto_discover=auto_discover
        )
    
    def _discover_and_register_plugins(
        self,
        category: str,  # Category name
        manager: Any  # Plugin manager instance
    ) -> List[PluginMetadata]:  # List of discovered plugin metadata
        """Discover plugins from manager and register their metadata."""
        discovered = manager.discover_plugins()
        plugin_metadatas = []
        
        for plugin_data in discovered:
            # Get config dataclass type from manager and convert to JSON schema
            config_dataclass = manager.get_plugin_config_dataclass(plugin_data.name)
            
            config_schema = dataclass_to_jsonschema(config_dataclass)
            
            # Create plugin metadata
            metadata = PluginMetadata(
                name=plugin_data.name,
                category=category,
                title=config_schema.get('title', plugin_data.name),
                config_schema=config_schema,
                config_dataclass=config_dataclass,
                version=plugin_data.version,
                description=config_schema.get('description')
            )
            
            # Check if plugin is configured
            config_file = self._config_dir / f"{metadata.get_unique_id()}.json"
            metadata.is_configured = config_file.exists()
            
            # Store metadata
            self._plugins[metadata.get_unique_id()] = metadata
            plugin_metadatas.append(metadata)
        
        return plugin_metadatas
    
    def get_manager(
        self,
        category: str,  # Category name
        manager_type: Optional[Type[T]] = None  # Optional type hint for IDE autocomplete
    ) -> Optional[T]:  # Plugin manager instance
        """Get plugin manager for a specific category."""
        return self._managers.get(category)
    
    def get_categories(self) -> List[str]:  # Sorted list of category names
        """Get all registered categories."""
        return sorted(self._categories.keys())
    
    def get_category_display_name(self, 
                                   category: str  # Category name
                                  ) -> str:  # Display name or category name if not set
        """Get display name for a category."""
        return self._categories.get(category, category.title())
    
    def get_plugin(self, 
                   unique_id: str  # Plugin unique identifier (format: 'category_name')
                  ) -> Optional[PluginMetadata]:  # Plugin metadata if found, None otherwise
        """Get plugin metadata by unique ID."""
        return self._plugins.get(unique_id)
    
    def get_plugins_by_category(self, 
                                category: str  # Category name
                               ) -> List[PluginMetadata]:  # List of plugin metadata for the category
        """Get all plugins in a category."""
        return [p for p in self._plugins.values() if p.category == category]
    
    def get_all_plugins(self) -> List[PluginMetadata]:  # List of all plugin metadata
        """Get all plugins across all categories."""
        return list(self._plugins.values())
    
    def get_categories_with_plugins(self) -> List[str]:  # Sorted list of categories with plugins
        """Get categories that have registered plugins."""
        categories = set(p.category for p in self._plugins.values())
        return sorted(categories)
    
    def load_plugin_config(self, 
                          unique_id: str  # Plugin unique identifier
                         ) -> Dict[str, Any]:  # Configuration dictionary (empty if no config exists)
        """Load saved configuration for a plugin."""
        config_file = self._config_dir / f"{unique_id}.json"
        if config_file.exists():
            with open(config_file, 'r') as f:
                return json.load(f)
        return {}
    
    def save_plugin_config(self, 
                          unique_id: str,  # Plugin unique identifier
                          config: Dict[str, Any]  # Configuration dictionary to save
                         ) -> bool:  # True if save succeeded, False otherwise
        """Save configuration for a plugin."""
        try:
            config_file = self._config_dir / f"{unique_id}.json"
            with open(config_file, 'w') as f:
                json.dump(config, f, indent=2)
            
            # Update plugin's configured status
            if unique_id in self._plugins:
                self._plugins[unique_id].is_configured = True
            
            return True
        except Exception as e:
            print(f"Error saving config for {unique_id}: {e}")
            return False
    
    def delete_plugin_config(self, 
                            unique_id: str  # Plugin unique identifier
                           ) -> bool:  # True if deletion succeeded, False otherwise
        """Delete saved configuration for a plugin."""
        try:
            config_file = self._config_dir / f"{unique_id}.json"
            if config_file.exists():
                config_file.unlink()
            
            # Update plugin's configured status
            if unique_id in self._plugins:
                self._plugins[unique_id].is_configured = False
            
            return True
        except Exception as e:
            print(f"Error deleting config for {unique_id}: {e}")
            return False
