"""
Example: Integrating EMDS Plugin with Engine Bridge

This example shows how to connect the QGIS plugin to the actual engine bridge
for processing workflows through NetWeaver, CDP, or other engines.

To use this:
1. Make sure engine_bridge.py is in your Python path
2. Add this to your emds_plugin.py or dock_widget.py
3. Connect workflow execution buttons to process_workflow_step()
"""

import sys
import json
from pathlib import Path
from typing import Dict, Any, Optional
import pandas as pd
from .qt_compat import QThread, pyqtSignal

# Add engine bridge to path (vendored inside the plugin folder)
sys.path.insert(0, str(Path(__file__).parent / 'python-bridge'))

try:
    from engine_bridge import NetWeaverBridge, CDPBridge
except ImportError:
    print("Warning: engine_bridge not found. Expected in emds_qgis_plugin/python-bridge/")
    NetWeaverBridge = None
    CDPBridge = None


class WorkflowExecutionThread(QThread):
    """Background thread for executing workflow steps"""

    progress_updated = pyqtSignal(str)  # Progress message
    execution_completed = pyqtSignal(dict)  # Results
    execution_failed = pyqtSignal(str)  # Error message

    def __init__(self, workflow_step, input_data: pd.DataFrame):
        super().__init__()
        self.workflow_step = workflow_step
        self.input_data = input_data

    def run(self):
        """Execute workflow step in background thread"""
        try:
            self.progress_updated.emit(f"Starting {self.workflow_step.name}...")

            # Determine which engine to use
            if self.workflow_step.engine_type.value == "NetWeaver":
                results = self._execute_netweaver()
            elif self.workflow_step.engine_type.value == "CDP":
                results = self._execute_cdp()
            else:
                results = self._execute_template()

            self.progress_updated.emit("Execution completed successfully")
            self.execution_completed.emit(results)

        except Exception as e:
            self.execution_failed.emit(f"Error: {str(e)}")

    def _execute_netweaver(self) -> Dict[str, Any]:
        """Execute NetWeaver engine"""
        if not NetWeaverBridge:
            raise RuntimeError("NetWeaver bridge not available")

        self.progress_updated.emit("Initializing NetWeaver bridge...")
        bridge = NetWeaverBridge()

        # Get parameters from workflow step
        model_file = self.workflow_step.parameters.get("model_file", "model.nw2")
        timeout = self.workflow_step.parameters.get("timeout", 300)

        self.progress_updated.emit(f"Processing with NetWeaver model: {model_file}")

        # Process data through NetWeaver
        results = bridge.process_data(
            input_data=self.input_data,
            model_file=model_file,
            timeout=timeout,
        )

        self.progress_updated.emit(f"NetWeaver processing complete: {len(results)} rows")

        return {
            "engine": "NetWeaver",
            "rows_processed": len(results),
            "output_data": results,
            "model_file": model_file,
        }

    def _execute_cdp(self) -> Dict[str, Any]:
        """Execute CDP engine"""
        if not CDPBridge:
            raise RuntimeError("CDP bridge not available")

        self.progress_updated.emit("Initializing CDP bridge...")
        bridge = CDPBridge()

        # Get parameters from workflow step
        config = self.workflow_step.parameters.get("config", "default.json")

        self.progress_updated.emit(f"Processing with CDP configuration: {config}")

        # Process data through CDP
        results = bridge.process_data(
            input_data=self.input_data,
            config_file=config,
        )

        self.progress_updated.emit(f"CDP processing complete: {len(results)} rows")

        return {
            "engine": "CDP",
            "rows_processed": len(results),
            "output_data": results,
            "config": config,
        }

    def _execute_template(self) -> Dict[str, Any]:
        """Execute template-based processing"""
        self.progress_updated.emit(f"Executing template: {self.workflow_step.name}")

        # Simulate template processing
        output_data = self.input_data.copy()

        # Example: Add a computed column
        if "geometry" in output_data.columns:
            output_data["area"] = output_data.geometry.area

        self.progress_updated.emit("Template processing complete")

        return {
            "engine": "Template",
            "rows_processed": len(output_data),
            "output_data": output_data,
        }


class WorkflowExecutor:
    """Helper class to execute workflows and manage results"""

    def __init__(self, project_manager, qgis_iface=None):
        """Initialize executor

        Args:
            project_manager: ProjectManager instance
            qgis_iface: QGIS interface for layer management
        """
        self.project_manager = project_manager
        self.iface = qgis_iface
        self.execution_threads: Dict[str, WorkflowExecutionThread] = {}

    def execute_step(
        self,
        project_id: str,
        assessment_id: str,
        provenance_id: str,
        workflow_step_id: str,
        input_data: pd.DataFrame,
    ):
        """Execute a workflow step

        Args:
            project_id: ID of the project
            assessment_id: ID of the assessment
            provenance_id: ID of the provenance
            workflow_step_id: ID of the workflow step
            input_data: Input data as pandas DataFrame
        """
        # Find the workflow step
        workflow_step = self.project_manager.find_workflow_step(
            project_id, assessment_id, provenance_id, workflow_step_id
        )

        if not workflow_step:
            raise ValueError(f"Workflow step {workflow_step_id} not found")

        # Create execution thread
        thread = WorkflowExecutionThread(workflow_step, input_data)

        # Store reference
        self.execution_threads[workflow_step_id] = thread

        return thread

    def load_layer_data(self, layer_name: str) -> Optional[pd.DataFrame]:
        """Load data from a QGIS layer into pandas DataFrame

        Args:
            layer_name: Name of the QGIS layer

        Returns:
            DataFrame with layer data, or None if layer not found
        """
        try:
            from qgis.core import QgsProject
            import geopandas as gpd

            project = QgsProject.instance()
            for layer in project.mapLayers().values():
                if layer.name() == layer_name:
                    # Convert to GeoDataFrame
                    return gpd.GeoDataFrame.from_features([feature for feature in layer.getFeatures()])

        except ImportError:
            print("Warning: geopandas not installed. Use pip install geopandas")
        except Exception as e:
            print(f"Error loading layer: {e}")

        return None

    def add_results_layer(
        self,
        layer_name: str,
        output_data: pd.DataFrame,
        project_id: str,
        assessment_id: str,
        provenance_id: str,
        workflow_step_id: str,
    ):
        """Add results as a new layer to the QGIS project

        Args:
            layer_name: Name for the output layer
            output_data: Pandas or GeoDataFrame with results
            project_id: Project ID for reference
            assessment_id: Assessment ID for reference
            provenance_id: Provenance ID for reference
            workflow_step_id: Workflow step ID for reference
        """
        try:
            from qgis.core import QgsProject, QgsVectorLayer
            import geopandas as gpd

            # Convert to GeoDataFrame if needed
            if not isinstance(output_data, gpd.GeoDataFrame):
                output_data = gpd.GeoDataFrame(output_data)

            # Create layer name with metadata
            full_layer_name = (
                f"{layer_name} "
                f"[{project_id[:8]}...{assessment_id[:8]}...{workflow_step_id[:8]}...]"
            )

            # Save to temporary GeoPackage or Shapefile
            temp_path = f"/tmp/{layer_name.replace(' ', '_')}.gpkg"
            output_data.to_file(temp_path, layer="results", driver="GPKG")

            # Add to QGIS
            project = QgsProject.instance()
            layer = QgsVectorLayer(temp_path, full_layer_name, "ogr")
            project.addMapLayer(layer)

            if self.iface:
                self.iface.mapCanvas().refresh()

            return layer

        except ImportError:
            print("Warning: geopandas not installed. Cannot add results layer.")
        except Exception as e:
            print(f"Error adding results layer: {e}")

        return None


# Example usage
if __name__ == "__main__":
    """
    Standalone example of workflow execution

    To use this:
    python3 example_integration.py
    """

    from models import (
        Project, Assessment, Provenance, WorkflowStep, Results,
        ProjectManager, EngineType
    )
    import uuid

    # Create sample data
    project_manager = ProjectManager()

    project = Project(
        id=str(uuid.uuid4()),
        name="Forest Analysis",
    )

    assessment = Assessment(
        id=str(uuid.uuid4()),
        name="Vegetation Cover",
        input_layers=["forest_mask", "land_use"],
    )
    project.add_assessment(assessment)

    provenance = Provenance(
        id=str(uuid.uuid4()),
        name="Processing Pipeline",
    )
    assessment.add_provenance(provenance)

    workflow_step = WorkflowStep(
        id=str(uuid.uuid4()),
        name="Calculate Intersection",
        engine_type=EngineType.NETWEAVER,
        parameters={"model_file": "intersection.nw2", "timeout": 300},
    )
    provenance.add_workflow_step(workflow_step)

    project_manager.add_project(project)

    # Create executor
    executor = WorkflowExecutor(project_manager)

    # Create sample input data
    sample_data = pd.DataFrame({
        "id": [1, 2, 3, 4, 5],
        "area": [100.5, 200.3, 150.2, 250.1, 175.8],
        "category": ["forest", "urban", "forest", "water", "urban"],
    })

    # Execute workflow step
    thread = executor.execute_step(
        project.id,
        assessment.id,
        provenance.id,
        workflow_step.id,
        sample_data,
    )

    # Connect signals (in QGIS, this would update the UI)
    thread.progress_updated.connect(lambda msg: print(f"Progress: {msg}"))
    thread.execution_completed.connect(lambda results: print(f"Results: {json.dumps(results, default=str, indent=2)}"))
    thread.execution_failed.connect(lambda error: print(f"Error: {error}"))

    # Start execution
    thread.start()
    thread.wait()
