import os
from PyQt5.QtWidgets import QAction, QMessageBox, QProgressBar, QDockWidget, QTextEdit
from PyQt5.QtGui import QIcon
from qgis.core import QgsProject, QgsVectorLayer, QgsFeature, QgsGeometry, QgsWkbTypes, QgsApplication
from qgis.PyQt.QtCore import Qt
from .main_plugin_dialog import DataLoaderDialog

class DataLoader:
    def __init__(self, iface):
        self.iface = iface
        self.plugin_dir = os.path.dirname(__file__)
        self.actions = []
        self.menu = self.tr(u'&Data Loader')
        self.toolbar = self.iface.addToolBar(u'DataLoader')
        self.toolbar.setObjectName(u'DataLoader')
        self.dlg = None
        self.description_dock = None

    def tr(self, message):
        return QgsApplication.translate('DataLoader', message)

    def add_action(self, icon_path, text, callback, enabled_by_default=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, parent=None):
        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_by_default)

        if add_to_menu:
            self.iface.addPluginToMenu(self.menu, action)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        self.actions.append(action)

        return action

    def initGui(self):
        icon_path = os.path.join(self.plugin_dir, 'resources', 'icon.png')
        
        # Add main plugin action
        self.add_action(
            icon_path,
            text=self.tr(u'Data Loader'),
            callback=self.run,
            parent=self.iface.mainWindow())

        # Add enhanced side window description with tips and usage guide
        self.description_dock = QDockWidget(self.tr('Data Loader Guide'), self.iface.mainWindow())
        self.description_dock.setObjectName('DataLoaderGuideDock')  # Set object name for QGIS to remember position
        self.description_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        
        description_text_edit = QTextEdit()
        description_text_edit.setReadOnly(True)
        description_html = """
<div style="font-family: Arial, sans-serif; line-height: 1.4;">
<h2 style="color: #2E7D32; border-bottom: 2px solid #4CAF50; padding-bottom: 5px;">🔄 Data Loader Plugin</h2>

<h3 style="color: #1976D2;">💡 Tips and Usage Guide</h3>

<h4 style="color: #1976D2;">🎯 Getting Started</h4>
<ul>
    <li><strong>Target Layer:</strong> The destination layer where new features will be added</li>
    <li><strong>Source Layer:</strong> The origin layer from which features will be copied</li>
    <li><strong>Field Mapping:</strong> Configure how source fields map to target fields</li>
</ul>

<h4 style="color: #1976D2;">📋 Prerequisites</h4>
<ul>
    <li>Both layers must be loaded in your QGIS project</li>
    <li>Layers should have compatible geometry types (Point→Point, Line→Line, etc.)</li>
    <li>Target layer should be editable</li>
    <li>Consider backing up your target layer before large operations</li>
</ul>

<h4 style="color: #1976D2;">⚙️ Field Mapping Rules</h4>
<ul>
    <li><strong>Automatic Matching:</strong> Fields with identical names are pre-selected</li>
    <li><strong>Type Compatibility:</strong> Only compatible field types are shown</li>
    <li><strong>Numeric Conversion:</strong> Different numeric types can be mapped to each other</li>
    <li><strong>String Conversion:</strong> Any field type can be converted to string</li>
    <li><strong>Unmapped Fields:</strong> Will use default values or remain empty</li>
</ul>

<h3 style="color: #1976D2;">📊 Supported Vector Data Sources</h3>
<ul>
    <li><strong>File Formats:</strong> Shapefile, GeoPackage, KML, GeoJSON, CSV with geometry</li>
    <li><strong>Databases:</strong> PostGIS, SpatiaLite, Oracle Spatial, SQL Server</li>
    <li><strong>Web Services:</strong> WFS, ArcGIS Feature Services</li>
    <li><strong>Memory Layers:</strong> Temporary and scratch layers</li>
    <li><strong>Virtual Layers:</strong> SQL-based virtual layers</li>
</ul>

<h4 style="color: #1976D2;">🗄️ PostGIS Support</h4>
<p><strong>✅ Full PostGIS Support:</strong> The plugin works seamlessly with PostGIS layers including:</p>
<ul>
    <li>Direct PostGIS table connections</li>
    <li>PostGIS views and materialized views</li>
    <li>Complex geometry types and spatial indexes</li>
    <li>Large PostGIS datasets with efficient processing</li>
    <li>Cross-database transfers (PostGIS ↔ other formats)</li>
</ul>

<h4 style="color: #1976D2;">🔍 Quality Checks</h4>
<ul>
    <li>Geometry type compatibility is automatically verified</li>
    <li>Field type compatibility is enforced during mapping</li>
    <li>Transaction rollback ensures data integrity on errors</li>
    <li>Progress tracking shows real-time status</li>
</ul>

<h4 style="color: #1976D2;">📊 Performance Tips</h4>
<ul>
    <li>For large datasets (>10,000 features), consider processing in batches</li>
    <li>Ensure both layers use the same coordinate reference system</li>
    <li>Close unnecessary applications to free up memory</li>
    <li>Monitor the log for progress updates and potential issues</li>
    <li>For PostGIS: Use spatial indexes for better performance</li>
</ul>

<h4 style="color: #1976D2;">🔧 Troubleshooting</h4>
<ul>
    <li><strong>No layers visible:</strong> Ensure vector layers are loaded in the project</li>
    <li><strong>Geometry errors:</strong> Check that geometry types are compatible</li>
    <li><strong>Field mapping issues:</strong> Verify field types are compatible</li>
    <li><strong>Performance:</strong> For large datasets, consider processing in smaller batches</li>
    <li><strong>PostGIS issues:</strong> Check database connection and permissions</li>
</ul>

<div style="margin-top: 15px; padding: 10px; background-color: #FFF3E0; border-left: 4px solid #FF9800;">
<strong>⚠️ Important:</strong> This operation will add features to your target layer. 
Make sure you have a backup if working with important data.
</div>

<div style="margin-top: 10px; padding: 10px; background-color: #E8F5E8; border-left: 4px solid #4CAF50;">
<strong>✅ Ready to start?</strong> Select your layers in the Parameters tab and configure field mappings. 
The Log tab will show detailed progress information during the process.
</div>

<h4 style="color: #1976D2;">📝 Log Messages</h4>
<p>The Log tab provides detailed processing information with color-coded messages:</p>
<ul>
    <li><span style="color: blue;"><strong>PROGRESS:</strong></span> Operation progress updates</li>
    <li><span style="color: green;"><strong>SUCCESS:</strong></span> Successful completion messages</li>
    <li><span style="color: orange;"><strong>WARNING:</strong></span> Non-critical issues</li>
    <li><span style="color: red;"><strong>ERROR:</strong></span> Critical errors requiring attention</li>
</ul>
</div>
"""
        description_text_edit.setHtml(description_html)
        self.description_dock.setWidget(description_text_edit)
        self.iface.addDockWidget(Qt.RightDockWidgetArea, self.description_dock)
        
        # Add menu action to show/hide the guide panel
        self.guide_action = self.add_action(
            icon_path,
            text=self.tr(u'Show/Hide Data Loader Guide'),
            callback=self.toggle_guide_panel,
            add_to_toolbar=False,  # Only in menu, not toolbar
            parent=self.iface.mainWindow())
        
        # Show the guide panel by default when plugin is first loaded
        self.description_dock.show()

    def toggle_guide_panel(self):
        """Toggle the visibility of the guide panel"""
        if self.description_dock.isVisible():
            self.description_dock.hide()
        else:
            self.description_dock.show()

    def unload(self):
        """Clean up when plugin is unloaded"""
        for action in self.actions:
            self.iface.removePluginMenu(self.tr(u'&Data Loader'), action)
            self.iface.removeToolBarIcon(action)
        
        # Clean up toolbar
        if hasattr(self, 'toolbar'):
            del self.toolbar
        
        # Clean up dock widget properly
        if hasattr(self, 'description_dock') and self.description_dock:
            self.description_dock.hide()
            self.iface.removeDockWidget(self.description_dock)
            self.description_dock.deleteLater()
            self.description_dock = None

    def run(self):
        self.dlg = DataLoaderDialog()
        
        # Override the show_guide_panel method to actually show our dock widget
        def show_guide():
            self.description_dock.show()
            self.description_dock.raise_()  # Bring to front
        
        self.dlg.show_guide_panel = show_guide
        
        # Show the dialog
        self.dlg.show()
        result = self.dlg.exec_()
        
        if result:
            # Validate inputs before processing
            is_valid, errors, warnings = self.dlg.validate_inputs()
            
            if not is_valid:
                self.dlg.show_validation_dialog(errors, warnings)
                return
            
            if warnings:
                if not self.dlg.show_validation_dialog(errors, warnings):
                    return  # User chose not to continue
            
            # Generate operation preview
            self.dlg.preview_operation()
            
            target_layer_id = self.dlg.combo_target_layer.currentData()
            source_layer_id = self.dlg.combo_source_layer.currentData()

            target_layer = QgsProject.instance().mapLayer(target_layer_id)
            source_layer = QgsProject.instance().mapLayer(source_layer_id)

            # Check geometry type compatibility
            if not self.check_geometry_compatibility(source_layer, target_layer):
                self.dlg.log_error("Incompatible geometry types between source and target layers.")
                QMessageBox.warning(self.iface.mainWindow(), "Data Loader", "Incompatible geometry types between source and target layers.")
                return

            field_map = self.dlg.get_field_mapping_summary()
            self.load_data(source_layer, target_layer, field_map)

    def check_geometry_compatibility(self, source_layer, target_layer):
        source_geom_type = source_layer.geometryType()
        target_geom_type = target_layer.geometryType()

        # Allow point to point, line to line, polygon to polygon
        if source_geom_type == target_geom_type:
            return True

        # Allow multi-part to single-part of the same type (e.g., MultiPoint to Point)
        if QgsWkbTypes.isSingleType(source_geom_type) and QgsWkbTypes.isMultiType(target_geom_type):
            if QgsWkbTypes.multiType(source_geom_type) == target_geom_type:
                return True
        if QgsWkbTypes.isMultiType(source_geom_type) and QgsWkbTypes.isSingleType(target_geom_type):
            if QgsWkbTypes.singleType(source_geom_type) == target_geom_type:
                return True

        return False

    def load_data(self, source_layer, target_layer, field_map):
        self.dlg.log_info("Starting data loading process...")
        self.dlg.log_info(f"Source layer: {source_layer.name()} ({source_layer.featureCount()} features)")
        self.dlg.log_info(f"Target layer: {target_layer.name()}")
        self.dlg.log_info(f"Field mappings: {len(field_map)} fields mapped")
        
        self.iface.mainWindow().statusBar().showMessage("Loading data...")
        progress_bar = QProgressBar()
        progress_bar.setMaximum(source_layer.featureCount())
        progress_bar.setValue(0)
        self.iface.mainWindow().statusBar().addPermanentWidget(progress_bar)

        target_layer.startEditing()
        features_processed = 0
        features_added = 0
        
        try:
            for i, source_feature in enumerate(source_layer.getFeatures()):
                new_feature = QgsFeature(target_layer.fields())
                new_feature.setGeometry(source_feature.geometry())

                # Map fields
                for target_field_name, source_field_name in field_map.items():
                    target_field_index = target_layer.fields().indexFromName(target_field_name)
                    source_field_index = source_layer.fields().indexFromName(source_field_name)

                    if target_field_index != -1 and source_field_index != -1:
                        source_value = source_feature[source_field_index]
                        new_feature[target_field_index] = source_value

                if target_layer.addFeature(new_feature):
                    features_added += 1
                
                features_processed += 1
                progress_bar.setValue(i + 1)
                
                # Log progress every 100 features or at the end
                if (i + 1) % 100 == 0 or (i + 1) == source_layer.featureCount():
                    self.dlg.log_progress(f"Processed {i+1}/{source_layer.featureCount()} features")

            target_layer.commitChanges()
            self.dlg.log_success(f"Data loaded successfully! {features_added} features added to {target_layer.name()}")
            self.dlg.log_info(f"Process completed. {features_processed} features processed, {features_added} features added.")
            QMessageBox.information(self.iface.mainWindow(), "Data Loader", f"Data loaded successfully!\n{features_added} features added.")
            
        except Exception as e:
            target_layer.rollBack()
            error_msg = f"Error loading data: {str(e)}"
            self.dlg.log_error(error_msg)
            self.dlg.log_error(f"Transaction rolled back. No changes made to {target_layer.name()}")
            QMessageBox.critical(self.iface.mainWindow(), "Data Loader", error_msg)
            
        finally:
            self.iface.mainWindow().statusBar().removeWidget(progress_bar)
            self.iface.mainWindow().statusBar().clearMessage()


