"""
QPredict - QGIS Plugin for GeoAI Inference

This plugin loads trained models from QModel Trainer (.qmtp format)
and applies them to raster layers for inference.

Main Plugin Class

This module contains the main plugin class that handles initialization,
UI creation, and coordination with the prediction manager.

Requires: QGeoAI Server running locally
Copyright (C) 2026 Nextelia®
Licensed under GPL v2+ - see LICENSE file
"""

from qgis.PyQt.QtWidgets import QAction, QToolBar
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import Qt
from qgis.core import QgsMessageLog, Qgis
import os


class QPredict:
    """
    Main plugin class for QPredict.
    
    This class handles:
    - Plugin initialization and cleanup
    - UI creation (dock widget)
    - Menu/toolbar integration
    - Connection between UI and prediction logic
    
    Args:
        iface: QGIS interface instance
    """
    
    def __init__(self, iface):
        """
        Initialize the plugin.
        
        Args:
            iface: QGIS interface instance (QgisInterface)
        """
        self.iface = iface
        self.plugin_dir = os.path.dirname(__file__)
        
        # UI components (initialized in initGui)
        self.dock_widget = None
        self.toolbar = None
        self.action = None
        
        # Prediction manager (initialized when needed)
        self.prediction_manager = None
        
        # QGeoAI Server client
        import sys
        from pathlib import Path
        qgeoai_path = str(Path.home() / '.qgeoai')
        if qgeoai_path not in sys.path:
            sys.path.insert(0, qgeoai_path)
        
        from qgeoai_client import QGeoAIClient
        self.client = QGeoAIClient()
    
    def initGui(self):
        """
        Create the plugin GUI elements.
        
        This method is called by QGIS when the plugin is loaded.
        It creates:
        - Action in the menu
        - Toolbar button
        - Dock widget (but doesn't show it yet)
        """
        
        # Start QGeoAI Server if not running (non-blocking)
        if not self.client.is_server_running():
            self.client.start_server(wait=False)
        
        # Create action that will start plugin configuration
        icon_path = os.path.join(self.plugin_dir, 'assets', 'images', 'icon.png')
        
        self.action = QAction(
            QIcon(icon_path),
            "QPredict",
            self.iface.mainWindow()
        )
        
        # Connect action to toggle dock
        self.action.triggered.connect(self.toggle_dock)
        
        # Add to QGeoAI submenu
        self.iface.addPluginToMenu("&QGeoAI", self.action)

        # Create or get shared QGeoAI toolbar
        self.toolbar = self.iface.mainWindow().findChild(QToolBar, 'QGeoAIToolbar')
        if not self.toolbar:
            self.toolbar = self.iface.addToolBar('QGeoAI')
            self.toolbar.setObjectName('QGeoAIToolbar')
        
        # Add to shared toolbar
        self.toolbar.addAction(self.action)
        
        # Log plugin loaded
        QgsMessageLog.logMessage(
            "QPredict plugin loaded successfully",
            "QPredict",
            Qgis.Info
        )
        
    def unload(self):
        """
        Remove the plugin GUI elements.
        
        This method is called by QGIS when the plugin is unloaded.
        """
        # Remove from QGeoAI menu
        self.iface.removePluginMenu("&QGeoAI", self.action)
        
        # Remove from toolbar
        if self.toolbar:
            self.toolbar.removeAction(self.action)
            
            # Remove toolbar if empty
            if len(self.toolbar.actions()) == 0:
                self.iface.mainWindow().removeToolBar(self.toolbar)
                self.toolbar.deleteLater()
        
        # Close and cleanup dock widget
        if self.dock_widget:
            self.dock_widget.close()
            self.dock_widget.deleteLater()
            self.dock_widget = None
        
        # Cleanup prediction manager if exists
        if self.prediction_manager:
            self.prediction_manager.cleanup()
            self.prediction_manager = None
        
        # Log plugin unloaded
        QgsMessageLog.logMessage(
            "QPredict plugin unloaded",
            "QPredict",
            Qgis.Info
        )
    
    def toggle_dock(self):
        """
        Show/hide the dock widget.
        
        Creates the dock widget on first call, then toggles visibility.
        """
        if not self.dock_widget:
            # Create dock widget (lazy initialization)
            from .ui.predict_dock import PredictDockWidget
            self.dock_widget = PredictDockWidget(self.iface.mainWindow())
            
            # Add dock to QGIS interface (right side by default)
            self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock_widget)
            
            # Connect dock signals (will be implemented later)
            self._connect_signals()
        
        # Toggle visibility
        if self.dock_widget.isVisible():
            self.dock_widget.hide()
        else:
            self.dock_widget.show()
    
    def _connect_signals(self):
        """
        Connect dock widget signals to plugin methods.
        """
        # Connect prediction control signals
        self.dock_widget.prediction_requested.connect(self.start_prediction)
        self.dock_widget.prediction_cancelled.connect(self.stop_prediction)
    
    def start_prediction(self):
        """
        Start prediction process - HTTP version.
        
        Creates PredictionManager with .qmtp path (model loading happens on server).
        """
        try:
            # Get configuration from dock
            config = self.dock_widget.get_prediction_config()
            
            # Get .qmtp path
            qmtp_path = self.dock_widget._qmtp_path
            if qmtp_path is None:
                self.dock_widget.append_log("\n❌ Model not loaded\n")
                self.dock_widget.on_prediction_cleanup()
                return
            
            # Get model info (from local validation)
            model_info = self.dock_widget._model_info
            if model_info is None:
                self.dock_widget.append_log("\n❌ Model info not available\n")
                self.dock_widget.on_prediction_cleanup()
                return
            
            # Create prediction manager (model will be loaded on server)
            from .managers.prediction_manager import PredictionManager
            
            self.dock_widget.append_log("\n🌐 Model will be loaded on server...")
            
            self.prediction_manager = PredictionManager(
                qmtp_path=qmtp_path, 
                model_info=model_info,
                config=config
            )
            
            # Connect signals
            self.prediction_manager.progress_updated.connect(
                self.dock_widget.update_progress
            )
            self.prediction_manager.log_message.connect(
                self.dock_widget.append_log
            )
            self.prediction_manager.prediction_finished.connect(
                self.on_prediction_finished
            )
            self.prediction_manager.prediction_failed.connect(
                self.on_prediction_failed
            )
            self.prediction_manager.cleanup_finished.connect(
                self.dock_widget.on_prediction_cleanup
            )
            
            # Start prediction in thread
            self.prediction_manager.start()
            
        except Exception as e:
            self.dock_widget.append_log(f"\n❌ Failed to start prediction: {str(e)}\n")
            self.dock_widget.on_prediction_cleanup()
    
    def stop_prediction(self):
        """
        Stop ongoing prediction.
        
        Requests graceful stop of prediction manager.
        """
        if self.prediction_manager and self.prediction_manager.isRunning():
            self.prediction_manager.request_stop()
    
    def on_prediction_finished(self, output_path: str):
        """
        Handle successful prediction completion.
        
        Args:
            output_path: Path to output file
        """
        self.dock_widget.append_log(f"\n🎉 Prediction complete! Output: {output_path}\n")
        
        # Cleanup manager
        if self.prediction_manager:
            self.prediction_manager.wait() 
            self.prediction_manager = None
    
    def on_prediction_failed(self, error_message: str):
        """
        Handle prediction failure.
        
        Args:
            error_message: Error description
        """
        self.dock_widget.append_log(f"\n❌ Prediction failed: {error_message}\n")
        
        # Cleanup manager
        if self.prediction_manager:
            self.prediction_manager.wait()
            self.prediction_manager = None