"""
Plugin manager for FileManager V2.

Handles:
- Plugin auto-discovery from BasePlugin._registry
- Plugin registration and enabling
- Dependency resolution
- Linting coordination across multiple linters
"""

import logging
from typing import List, Optional, Set, Dict, Any

from .base import BasePlugin, LinterPlugin
from ..models import LintResults

logger = logging.getLogger(__name__)


class PluginManager:
    """Manages plugins for FileManager scaffold."""

    def __init__(self, auto_discover: bool = True):
        """
        Initialize plugin manager.

        Args:
            auto_discover: Whether to auto-discover plugins from registry
        """
        self.plugins: List[BasePlugin] = []
        self.enabled_plugins: Set[str] = set()
        self.linter_plugins: List[LinterPlugin] = []

        if auto_discover:
            self._discover_plugins()

    def _discover_plugins(self):
        """Auto-discover plugins from BasePlugin._registry."""
        for plugin_name, plugin_class in BasePlugin._registry.items():
            try:
                # Instantiate plugin with no config
                plugin_instance = plugin_class()
                self.register_plugin(plugin_instance)
                logger.debug(f"Discovered plugin: {plugin_name}")
            except Exception as e:
                logger.warning(f"Failed to instantiate plugin {plugin_name}: {e}")

    def register_plugin(self, plugin: BasePlugin):
        """
        Register plugin (not enabled yet).

        Args:
            plugin: Plugin instance to register
        """
        # Check if already registered
        if self.get_plugin_by_name(plugin.name):
            return

        self.plugins.append(plugin)

        # Track linter plugins separately
        if isinstance(plugin, LinterPlugin):
            self.linter_plugins.append(plugin)
            logger.debug(f"Registered linter plugin: {plugin.name}")

    def enable_plugin(self, plugin_name: str, _resolving_deps: Optional[Set[str]] = None):
        """
        Enable plugin with dependency resolution.

        Args:
            plugin_name: Name of plugin to enable
            _resolving_deps: Internal set for circular dependency detection

        Raises:
            ValueError: If plugin not found or circular dependency detected
        """
        if _resolving_deps is None:
            _resolving_deps = set()

        # Already enabled
        if plugin_name in self.enabled_plugins:
            return

        # Circular dependency check
        if plugin_name in _resolving_deps:
            raise ValueError(f"Circular dependency detected: {plugin_name}")

        # Get plugin
        plugin = self.get_plugin_by_name(plugin_name)
        if not plugin:
            raise ValueError(f"Plugin not found: {plugin_name}")

        # Track resolution
        _resolving_deps.add(plugin_name)

        # Resolve dependencies
        dependencies = getattr(plugin.__class__, 'dependencies', [])
        for dep in dependencies:
            self.enable_plugin(dep, _resolving_deps)

        # Enable plugin
        self.enabled_plugins.add(plugin_name)
        plugin.on_plugin_enabled(self)
        logger.info(f"Enabled plugin: {plugin_name}")

        # Clean up resolution tracking
        _resolving_deps.discard(plugin_name)

    def disable_plugin(self, plugin_name: str):
        """
        Disable plugin.

        Args:
            plugin_name: Name of plugin to disable
        """
        if plugin_name in self.enabled_plugins:
            self.enabled_plugins.discard(plugin_name)
            logger.info(f"Disabled plugin: {plugin_name}")

    def lint_file(self, path: str, content: str) -> LintResults:
        """
        Run all applicable linters on file.

        Args:
            path: File path
            content: File content

        Returns:
            Aggregated LintResults from all linters
        """
        all_results = LintResults()

        for linter in self.linter_plugins:
            # Skip disabled linters
            if linter.name not in self.enabled_plugins:
                continue

            # Skip if linter can't handle this file type
            if not linter.can_handle_file(path):
                continue

            try:
                # Run linter
                results = linter.lint_content(path, content)

                # Aggregate results
                all_results.errors.extend(results.errors)
                all_results.warnings.extend(results.warnings)
                all_results.info.extend(results.info)
                all_results.linter_runs[linter.name] = True

                logger.debug(f"Linter {linter.name} completed: {len(results.errors)} errors, {len(results.warnings)} warnings")

            except Exception as e:
                logger.warning(f"Linter {linter.name} failed: {e}")
                all_results.linter_runs[linter.name] = False

        return all_results

    def get_plugin_by_name(self, name: str) -> Optional[BasePlugin]:
        """
        Get plugin by name.

        Args:
            name: Plugin name

        Returns:
            Plugin instance or None if not found
        """
        for plugin in self.plugins:
            if plugin.name == name:
                return plugin
        return None

    def get_enabled_linters(self) -> List[LinterPlugin]:
        """
        Get list of enabled linter plugins.

        Returns:
            List of enabled LinterPlugin instances
        """
        return [
            linter for linter in self.linter_plugins
            if linter.name in self.enabled_plugins
        ]

    def configure_plugin(self, plugin_name: str, config: Dict[str, Any]):
        """
        Re-configure an existing plugin.

        Args:
            plugin_name: Plugin name
            config: New configuration dict

        Raises:
            ValueError: If plugin not found
        """
        plugin = self.get_plugin_by_name(plugin_name)
        if not plugin:
            raise ValueError(f"Plugin not found: {plugin_name}")

        # Get plugin class
        plugin_class = type(plugin)

        # Create new instance with config
        try:
            configured_plugin = plugin_class(config=config)

            # Replace in plugin lists
            self.plugins.remove(plugin)
            self.plugins.append(configured_plugin)

            if isinstance(plugin, LinterPlugin):
                self.linter_plugins.remove(plugin)
                self.linter_plugins.append(configured_plugin)

            logger.info(f"Reconfigured plugin: {plugin_name}")

        except Exception as e:
            logger.error(f"Failed to reconfigure plugin {plugin_name}: {e}")
            raise
