#!/usr/bin/env python3
#
# Copyright (c) 2025 Stormux
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

"""PluginManager plugin for Cthulhu - GUI interface for managing plugins."""

import logging
import os
import configparser
from pathlib import Path

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, Pango

from cthulhu.plugin import Plugin, cthulhu_hookimpl
from cthulhu import cthulhu
from cthulhu import debug

logger = logging.getLogger(__name__)


class PluginManager(Plugin):
    """Plugin that provides a GUI interface for managing other plugins."""

    PLUGIN_COL_ENABLED = 0
    PLUGIN_COL_DISPLAY = 1
    PLUGIN_COL_CAN_TOGGLE = 2
    PLUGIN_COL_NAME = 3
    
    def __init__(self, *args, **kwargs):
        """Initialize the PluginManager plugin."""
        super().__init__(*args, **kwargs)
        self._kb_binding = None
        self._dialog = None
        self._plugin_treeview = None
        self._plugin_model = None
        self._activated = False
        
        debug.printMessage(debug.LEVEL_INFO, "PluginManager: Plugin initialized", True)
    
    @cthulhu_hookimpl
    def activate(self, plugin=None):
        """Activate the PluginManager plugin."""
        if plugin is not None and plugin is not self:
            return
            
        # Prevent duplicate activation
        if self._activated:
            debug.printMessage(debug.LEVEL_INFO, "PluginManager: Already activated, skipping", True)
            return
            
        try:
            debug.printMessage(debug.LEVEL_INFO, "PluginManager: Plugin activation starting", True)
            
            self._activated = True
            debug.printMessage(debug.LEVEL_INFO, "PluginManager: Plugin activated successfully", True)
            return True
            
        except Exception as e:
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: ERROR activating plugin: {e}", True)
            return False
    
    @cthulhu_hookimpl  
    def deactivate(self, plugin=None):
        """Deactivate the PluginManager plugin."""
        if plugin is not None and plugin is not self:
            return
            
        try:
            debug.printMessage(debug.LEVEL_INFO, "PluginManager: Plugin deactivation starting", True)
            
            # Close dialog if open
            if self._dialog:
                self._dialog.destroy()
                self._dialog = None
            
            self._activated = False
            debug.printMessage(debug.LEVEL_INFO, "PluginManager: Plugin deactivated successfully", True)
            return True
            
        except Exception as e:
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: ERROR deactivating plugin: {e}", True)
            return False
    
    def _register_keybinding(self):
        """Register the Cthulhu+Shift+P keybinding for opening plugin manager."""
        try:
            if not self.app:
                debug.printMessage(debug.LEVEL_INFO, "PluginManager: ERROR - No app reference available for keybinding", True)
                return
            
            # Register Cthulhu+Shift+P keybinding
            gesture_string = "kb:cthulhu+shift+p"
            description = "Open plugin manager"
            
            self._kb_binding = self.registerGestureByString(
                self._open_plugin_manager, 
                description, 
                gesture_string
            )
            
            if self._kb_binding:
                debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Registered keybinding {gesture_string}", True)
            else:
                debug.printMessage(debug.LEVEL_INFO, f"PluginManager: ERROR - Failed to register keybinding {gesture_string}", True)
                
        except Exception as e:
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: ERROR registering keybinding: {e}", True)
    
    def _open_plugin_manager(self, script, inputEvent=None):
        """Open the plugin manager dialog."""
        try:
            debug.printMessage(debug.LEVEL_INFO, "PluginManager: Opening plugin manager dialog", True)
            
            # Close existing dialog if open
            if self._dialog:
                self._dialog.destroy()
            
            # Create new dialog
            self._create_dialog()
            
            return True
            
        except Exception as e:
            logger.error(f"PluginManager: Error opening plugin manager: {e}")
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error opening dialog: {e}", True)
            return False
    
    def _create_dialog(self):
        """Create and show the plugin manager dialog."""
        try:
            # Create dialog window
            self._dialog = Gtk.Dialog(
                title="Cthulhu Plugin Manager",
                parent=None,
                flags=Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT
            )
            
            # Set dialog properties
            self._dialog.set_default_size(400, 300)
            self._dialog.set_border_width(10)
            
            # Add buttons
            self._dialog.add_button("Close", Gtk.ResponseType.CLOSE)
            
            # Create main content area
            content_area = self._dialog.get_content_area()
            
            # Add title label
            title_label = Gtk.Label()
            title_label.set_markup("<b>Available Plugins</b>")
            title_label.set_halign(Gtk.Align.CENTER)
            content_area.pack_start(title_label, False, False, 10)
            
            # Add info label about PluginManager
            info_label = Gtk.Label()
            info_label.set_markup("<i>Note:To apply changes, restart Cthulhu</i>")
            info_label.set_halign(Gtk.Align.CENTER)
            content_area.pack_start(info_label, False, False, 5)
            
            # Create scrolled window for plugin list
            scrolled = Gtk.ScrolledWindow()
            scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
            scrolled.set_size_request(-1, 200)

            self._plugin_model = Gtk.TreeStore(bool, str, bool, str)
            self._plugin_treeview = Gtk.TreeView(model=self._plugin_model)
            self._plugin_treeview.set_headers_visible(True)
            self._plugin_treeview.set_enable_search(False)
            self._plugin_treeview.connect("key-press-event", self._on_plugin_list_key_press)
            self._plugin_treeview.connect("row-activated", self._on_plugin_row_activated)

            toggle_renderer = Gtk.CellRendererToggle()
            toggle_renderer.set_activatable(True)
            toggle_renderer.connect("toggled", self._on_plugin_toggled)
            toggle_column = Gtk.TreeViewColumn(
                "Enabled",
                toggle_renderer,
                active=self.PLUGIN_COL_ENABLED,
                activatable=self.PLUGIN_COL_CAN_TOGGLE
            )
            toggle_column.add_attribute(toggle_renderer, "visible", self.PLUGIN_COL_CAN_TOGGLE)
            self._plugin_treeview.append_column(toggle_column)

            text_renderer = Gtk.CellRendererText()
            text_renderer.set_property("ellipsize", Pango.EllipsizeMode.END)
            text_column = Gtk.TreeViewColumn(
                "Plugin",
                text_renderer,
                text=self.PLUGIN_COL_DISPLAY
            )
            text_column.set_expand(True)
            self._plugin_treeview.append_column(text_column)

            scrolled.add(self._plugin_treeview)
            
            content_area.pack_start(scrolled, True, True, 0)
            
            # Populate plugin list
            self._populate_plugin_list()
            
            # Connect signals
            self._dialog.connect("response", self._on_dialog_response)
            
            # Show dialog
            self._dialog.show_all()
            
            debug.printMessage(debug.LEVEL_INFO, "PluginManager: Dialog created and shown", True)
            
        except Exception as e:
            logger.error(f"PluginManager: Error creating dialog: {e}")
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error creating dialog: {e}", True)
    
    def _populate_plugin_list(self):
        """Populate the plugin list with available plugins."""
        try:
            # Get available plugins
            available_plugins = self._discover_plugins()
            
            # Get currently active plugins
            active_plugins = cthulhu.cthulhuApp.settingsManager.getSetting('activePlugins') or []
            
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Found {len(available_plugins)} plugins", True)
            
            # Clear existing model rows
            self._plugin_model.clear()

            # Add each plugin as a checkbox (except PluginManager itself)
            enabled_iter = self._plugin_model.append(
                None,
                [False, "Enabled plugins", False, ""]
            )
            disabled_iter = self._plugin_model.append(
                None,
                [False, "Disabled plugins", False, ""]
            )

            for plugin_name, plugin_info in sorted(available_plugins.items()):
                # Skip PluginManager to prevent users from disabling plugin management
                if plugin_name == "PluginManager":
                    continue
                    
                display_name = plugin_info.get('name', plugin_name)
                display_text = display_name
                description = plugin_info.get('description')
                if description:
                    display_text += f" - {description}"
                version = plugin_info.get('version')
                if version:
                    display_text += f" (v{version})"

                is_active = plugin_name in active_plugins
                parent_iter = enabled_iter if is_active else disabled_iter
                self._plugin_model.append(
                    parent_iter,
                    [is_active, display_text, True, plugin_name]
                )

            self._plugin_treeview.collapse_all()
            
        except Exception as e:
            logger.error(f"PluginManager: Error populating plugin list: {e}")
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error populating list: {e}", True)
    
    def _discover_plugins(self):
        """Discover all available plugins."""
        plugins = {}
        
        try:
            # Get plugin system manager
            from cthulhu import plugin_system_manager
            
            # Use existing plugin manager to get plugins
            manager = plugin_system_manager.getManager()
            if manager:
                manager.rescanPlugins()
                
                for plugin_info in manager.plugins:
                    plugin_name = plugin_info.get_module_name()
                    plugins[plugin_name] = {
                        'name': plugin_info.get_name(),
                        'description': plugin_info.get_description(),
                        'version': plugin_info.get_version(),
                        'path': plugin_info.get_module_dir()
                    }
            else:
                # Fallback: manually scan plugin directories
                plugins = self._manual_plugin_discovery()
            
        except Exception as e:
            logger.error(f"PluginManager: Error in plugin discovery: {e}")
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Plugin discovery error: {e}", True)
            # Fallback to manual discovery
            plugins = self._manual_plugin_discovery()
        
        return plugins
    
    def _manual_plugin_discovery(self):
        """Manually discover plugins by scanning directories."""
        plugins = {}
        
        try:
            # Get plugin directories
            from cthulhu.plugin_system_manager import PluginType
            
            system_dir = PluginType.SYSTEM.get_root_dir()
            user_dir = PluginType.USER.get_root_dir()
            
            for plugin_dir in [system_dir, user_dir]:
                if os.path.exists(plugin_dir):
                    self._scan_plugin_directory(plugin_dir, plugins)
            
        except Exception as e:
            logger.error(f"PluginManager: Error in manual discovery: {e}")
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Manual discovery error: {e}", True)
        
        return plugins
    
    def _scan_plugin_directory(self, directory, plugins):
        """Scan a directory for plugins."""
        try:
            for item in os.listdir(directory):
                plugin_path = os.path.join(directory, item)
                if os.path.isdir(plugin_path):
                    # Check for plugin.py and plugin.info
                    plugin_py = os.path.join(plugin_path, "plugin.py")
                    plugin_info_file = os.path.join(plugin_path, "plugin.info")
                    
                    if os.path.exists(plugin_py):
                        plugin_info = {'name': item, 'description': '', 'version': ''}
                        
                        # Try to read plugin.info
                        if os.path.exists(plugin_info_file):
                            try:
                                config = configparser.ConfigParser()
                                config.read(plugin_info_file)
                                
                                # Handle both INI-style and simple key=value format
                                if config.sections():
                                    # INI-style format
                                    for section in config.sections():
                                        for key, value in config[section].items():
                                            if key.lower() in ['description', 'version']:
                                                plugin_info[key.lower()] = value
                                else:
                                    # Simple key=value format
                                    with open(plugin_info_file, 'r') as f:
                                        for line in f:
                                            line = line.strip()
                                            if '=' in line and not line.startswith('#'):
                                                key, value = line.split('=', 1)
                                                key = key.strip().lower()
                                                value = value.strip()
                                                if key in ['description', 'version']:
                                                    plugin_info[key] = value
                            except Exception as info_e:
                                debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error reading {plugin_info_file}: {info_e}", True)
                        
                        plugins[item] = plugin_info
                        
        except Exception as e:
            logger.error(f"PluginManager: Error scanning directory {directory}: {e}")
    
    def _on_plugin_toggled(self, renderer, path):
        """Handle plugin toggle via TreeView."""
        try:
            tree_iter = self._plugin_model.get_iter(path)
            if not tree_iter:
                return

            can_toggle = self._plugin_model.get_value(tree_iter, self.PLUGIN_COL_CAN_TOGGLE)
            if not can_toggle:
                return

            is_active = self._plugin_model.get_value(tree_iter, self.PLUGIN_COL_ENABLED)
            plugin_name = self._plugin_model.get_value(tree_iter, self.PLUGIN_COL_NAME)
            new_active = not is_active
            self._plugin_model.set_value(tree_iter, self.PLUGIN_COL_ENABLED, new_active)
            self._set_plugin_active(plugin_name, new_active)
            self._rebuild_plugin_groups()
        except Exception as error:
            logger.error(f"PluginManager: Error toggling plugin at path {path}: {error}")
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error toggling plugin at path {path}: {error}", True)

    def _on_plugin_list_key_press(self, widget, event):
        """Toggle plugin on Space while keeping Tab navigation outside the list."""
        if event.keyval != Gdk.KEY_space:
            return False

        selection = self._plugin_treeview.get_selection()
        model, tree_iter = selection.get_selected()
        if not tree_iter:
            return False

        path = model.get_path(tree_iter)
        self._on_plugin_toggled(None, path)
        return True

    def _on_plugin_row_activated(self, treeview, path, column):
        """Toggle plugin when activating a row."""
        self._on_plugin_toggled(None, path)

    def _rebuild_plugin_groups(self):
        """Rebuild the tree so enabled/disabled groups stay accurate."""
        if not self._plugin_model:
            return

        selection = self._plugin_treeview.get_selection()
        model, tree_iter = selection.get_selected()
        selected_name = None
        if tree_iter:
            selected_name = model.get_value(tree_iter, self.PLUGIN_COL_NAME)

        self._populate_plugin_list()

        if selected_name:
            self._select_plugin_row(selected_name)

    def _select_plugin_row(self, plugin_name):
        """Select the row for the given plugin name."""
        def _walk(model, tree_iter):
            while tree_iter:
                name = model.get_value(tree_iter, self.PLUGIN_COL_NAME)
                if name == plugin_name:
                    path = model.get_path(tree_iter)
                    self._plugin_treeview.expand_to_path(path)
                    self._plugin_treeview.get_selection().select_path(path)
                    return True
                if model.iter_has_child(tree_iter):
                    child = model.iter_children(tree_iter)
                    if _walk(model, child):
                        return True
                tree_iter = model.iter_next(tree_iter)
            return False

        root = self._plugin_model.get_iter_first()
        _walk(self._plugin_model, root)

    def _set_plugin_active(self, plugin_name, is_active):
        """Update settings to enable or disable a plugin."""
        try:
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Plugin {plugin_name} toggled to {'active' if is_active else 'inactive'}", True)

            # Get current active plugins
            active_plugins = cthulhu.cthulhuApp.settingsManager.getSetting('activePlugins') or []
            active_plugins = list(active_plugins)

            if is_active and plugin_name not in active_plugins:
                active_plugins.append(plugin_name)
            elif not is_active and plugin_name in active_plugins:
                active_plugins.remove(plugin_name)

            cthulhu.cthulhuApp.settingsManager.setSetting('activePlugins', active_plugins)
            if hasattr(cthulhu.cthulhuApp.settingsManager, "general") and isinstance(cthulhu.cthulhuApp.settingsManager.general, dict):
                cthulhu.cthulhuApp.settingsManager.general['activePlugins'] = active_plugins

            try:
                active_profile = cthulhu.cthulhuApp.settingsManager.getSetting('activeProfile')
                if isinstance(active_profile, (list, tuple)) and len(active_profile) > 1:
                    profile_name = active_profile[1]
                else:
                    profile_name = cthulhu.cthulhuApp.settingsManager.profile or 'default'

                current_general = cthulhu.cthulhuApp.settingsManager.getGeneralSettings(profile_name) or {}
                current_general['activePlugins'] = active_plugins

                cthulhu.cthulhuApp.settingsManager.profile = profile_name
                cthulhu.cthulhuApp.settingsManager.saveProfileSettings(current_general)
                debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Settings saved via settings manager (profile {profile_name})", True)

            except Exception as save_error:
                debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error saving plugin state: {save_error}", True)

            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Updated active plugins: {active_plugins}", True)

            try:
                from cthulhu import plugin_system_manager
                manager = plugin_system_manager.getManager()
                if manager:
                    manager.setActivePlugins(active_plugins)
                    debug.printMessage(debug.LEVEL_INFO, "PluginManager: Applied active plugin changes", True)
            except Exception as apply_error:
                debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Failed to apply plugin changes: {apply_error}", True)

        except Exception as error:
            logger.error(f"PluginManager: Error toggling plugin {plugin_name}: {error}")
            debug.printMessage(debug.LEVEL_INFO, f"PluginManager: Error toggling {plugin_name}: {error}", True)
    
    
    def _on_dialog_response(self, dialog, response_id):
        """Handle dialog response (close button clicked)."""
        try:
            if response_id == Gtk.ResponseType.CLOSE:
                dialog.destroy()
                self._dialog = None
                debug.printMessage(debug.LEVEL_INFO, "PluginManager: Dialog closed", True)
                
        except Exception as e:
            logger.error(f"PluginManager: Error handling dialog response: {e}")
