"""
Execution UI Extensions for EMDS Dock Widget

Adds execution controls, progress feedback, and results management to the main dock widget.
This module integrates with executor.py to provide background workflow execution.

Author: EMDS QGIS Port POC
Date: 2025-11-07
"""

from .qt_compat import (
    QApplication, QDockWidget, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,
    QProgressBar, QDialog, QTableWidget, QTableWidgetItem, QMessageBox,
    QTabWidget, QTextEdit
)
from .qt_compat import Qt, pyqtSignal, QTimer, QIcon, QColor
from typing import Optional, Dict, Any
import pandas as pd

from .executor import WorkflowExecutor
from .models import WorkflowStep, ProjectManager
from .results_manager import ResultsManager, ExecutionStatus
from .results_grid_dialog import ResultsGridDialog
from .qt_compat import exec_dialog
from .theme import muted_text_color


class ExecutionProgressDialog(QDialog):
    """Dialog showing execution progress"""

    execution_cancelled = pyqtSignal()

    def __init__(self, workflow_step: WorkflowStep, parent=None):
        super().__init__(parent)
        self.workflow_step = workflow_step
        self.execution_id = None
        self.init_ui()

    def init_ui(self):
        """Initialize UI"""
        self.setWindowTitle(f"Running Task: {self.workflow_step.name}")
        self.setMinimumWidth(550)
        self.setMinimumHeight(320)
        self.setModal(True)

        layout = QVBoxLayout()

        # Title
        title_label = QLabel(f"<b>Running task:</b> {self.workflow_step.name}")
        layout.addWidget(title_label)

        # Current step label (large, descriptive)
        self.step_label = QLabel("Preparing execution...")
        self.step_label.setStyleSheet("font-size: 13px; margin: 4px 0;")
        layout.addWidget(self.step_label)

        # Progress bar
        self.progress_bar = QProgressBar()
        self.progress_bar.setMinimum(0)
        self.progress_bar.setMaximum(0)  # Start in indeterminate/pulsing mode
        self.progress_bar.setTextVisible(False)
        layout.addWidget(self.progress_bar)

        # Row below progress bar: percentage on left, elapsed time on right
        info_row = QHBoxLayout()
        self.progress_label = QLabel("")
        info_row.addWidget(self.progress_label)
        info_row.addStretch()
        self.elapsed_label = QLabel("Elapsed: 0s")
        self.elapsed_label.setStyleSheet(f"color: {muted_text_color()};")
        info_row.addWidget(self.elapsed_label)
        layout.addLayout(info_row)

        # Activity log (scrolling text area)
        self.activity_log = QTextEdit()
        self.activity_log.setReadOnly(True)
        self.activity_log.setMaximumHeight(100)
        self.activity_log.setStyleSheet("font-size: 11px; color: #555; background: #f9f9f9;")
        self.activity_log.setPlaceholderText("Activity log...")
        layout.addWidget(self.activity_log)

        # Status label
        self.status_label = QLabel("")
        self.status_label.setStyleSheet(f"color: {muted_text_color()}; font-size: 10px;")
        layout.addWidget(self.status_label)

        # Cancel button
        button_layout = QHBoxLayout()
        self.btn_cancel = QPushButton("Cancel")
        self.btn_cancel.clicked.connect(self.on_cancel)
        button_layout.addStretch()
        button_layout.addWidget(self.btn_cancel)
        layout.addLayout(button_layout)

        self.setLayout(layout)

        # Elapsed time timer
        self._elapsed_seconds = 0
        self._elapsed_timer = QTimer(self)
        self._elapsed_timer.timeout.connect(self._update_elapsed)
        self._elapsed_timer.start(1000)

    def update_progress(self, message: str, percentage: int):
        """Update progress display"""
        # Switch from indeterminate to determinate mode on first real progress
        if self.progress_bar.maximum() == 0 and percentage > 0:
            self.progress_bar.setMaximum(100)
            self.progress_bar.setTextVisible(True)

        self.progress_bar.setValue(percentage)

        # Update step label with the main message
        self.step_label.setText(message)

        # Update percentage label
        self.progress_label.setText(f"{percentage}%")

        # Append to activity log (avoid duplicates for same message)
        self.activity_log.append(message)

        # Auto-scroll to bottom
        scrollbar = self.activity_log.verticalScrollBar()
        scrollbar.setValue(scrollbar.maximum())
        QApplication.processEvents()

    def _update_elapsed(self):
        """Update the elapsed time display"""
        self._elapsed_seconds += 1
        minutes, seconds = divmod(self._elapsed_seconds, 60)
        if minutes > 0:
            self.elapsed_label.setText(f"Elapsed: {minutes}m {seconds}s")
        else:
            self.elapsed_label.setText(f"Elapsed: {seconds}s")

    def show(self):
        """Show dialog and reset timer"""
        self._elapsed_seconds = 0
        self._elapsed_timer.start(1000)
        super().show()
        QApplication.processEvents()

    def on_cancel(self):
        """User clicked cancel"""
        self.execution_cancelled.emit()
        self.reject()

    def set_execution_id(self, execution_id: str):
        """Set execution ID"""
        self.execution_id = execution_id


class ResultsViewerDialog(ResultsGridDialog):
    """Backwards-compatible wrapper around the reusable results grid viewer."""

    @classmethod
    def from_payload(
        cls,
        *,
        execution_id: str,
        results_df: pd.DataFrame = None,
        title: Optional[str] = None,
        subtitle: Optional[str] = None,
        parent=None,
        database_path: str = "",
        table_name: str = "",
    ) -> "ResultsViewerDialog":
        dialog = cls(
            execution_id,
            results_df,
            parent,
            database_path=database_path,
            table_name=table_name,
        )
        if title:
            dialog.setWindowTitle(title)
            dialog.title_text = title
        if subtitle is not None:
            dialog.subtitle_text = subtitle
        return dialog

    def __init__(
        self,
        execution_id: str,
        results_df: pd.DataFrame = None,
        parent=None,
        *,
        database_path: str = "",
        table_name: str = "",
    ):
        subtitle = f"Execution Results: {execution_id}"
        super().__init__(
            dataframe=results_df,
            title=f"Results: {execution_id}",
            subtitle=subtitle,
            parent=parent,
            database_path=database_path,
            table_name=table_name,
            layer_name_hint=table_name or f"Results-{execution_id[:8]}",
        )


class ExecutionHistoryDialog(QDialog):
    """Dialog for viewing execution history"""

    def __init__(self, workflow_step_id: str, results_manager: ResultsManager, parent=None):
        super().__init__(parent)
        self.workflow_step_id = workflow_step_id
        self.results_manager = results_manager
        self.init_ui()

    def init_ui(self):
        """Initialize UI"""
        self.setWindowTitle(f"Execution History")
        self.setMinimumWidth(900)
        self.setMinimumHeight(500)

        layout = QVBoxLayout()

        # Title
        title_label = QLabel(f"Execution History for Task: {self.workflow_step_id}")
        layout.addWidget(title_label)

        # History table
        self.history_table = QTableWidget()
        self.history_table.setColumnCount(6)
        self.history_table.setHorizontalHeaderLabels([
            "Execution ID", "Status", "Start Time", "Duration (ms)", "Rows", "Error"
        ])
        layout.addWidget(self.history_table)

        # Close button
        button_layout = QHBoxLayout()
        btn_close = QPushButton("Close")
        btn_close.clicked.connect(self.accept)
        button_layout.addStretch()
        button_layout.addWidget(btn_close)
        layout.addLayout(button_layout)

        self.setLayout(layout)

        # Load history
        self._load_history()

    def _load_history(self):
        """Load execution history"""
        executions = self.results_manager.get_workflow_executions(self.workflow_step_id)

        self.history_table.setRowCount(len(executions))

        for row_idx, execution in enumerate(executions):
            # Execution ID
            item = QTableWidgetItem(execution.execution_id[:8] + "...")
            self.history_table.setItem(row_idx, 0, item)

            # Status (with color coding)
            status_item = QTableWidgetItem(execution.status.value)
            if execution.status == ExecutionStatus.COMPLETED:
                status_item.setBackground(QColor(200, 255, 200))
            elif execution.status == ExecutionStatus.FAILED:
                status_item.setBackground(QColor(255, 200, 200))
            elif execution.status == ExecutionStatus.RUNNING:
                status_item.setBackground(QColor(200, 200, 255))
            self.history_table.setItem(row_idx, 1, status_item)

            # Start time
            item = QTableWidgetItem(execution.start_time)
            self.history_table.setItem(row_idx, 2, item)

            # Duration
            item = QTableWidgetItem(str(execution.duration_ms))
            self.history_table.setItem(row_idx, 3, item)

            # Rows processed
            item = QTableWidgetItem(str(execution.rows_processed))
            self.history_table.setItem(row_idx, 4, item)

            # Error message
            error = execution.error_message or ""
            item = QTableWidgetItem(error[:50])
            if error:
                item.setToolTip(error)
            self.history_table.setItem(row_idx, 5, item)

        # Auto-resize columns
        self.history_table.resizeColumnsToContents()


class DockWidgetExecutorMixin:
    """
    Mixin to add execution capabilities to EMDSDockWidget

    Usage:
        class EMDSDockWidget(QDockWidget, DockWidgetExecutorMixin):
            def __init__(self, iface, parent=None):
                super().__init__(iface, parent)
                self.init_executor()
    """

    def init_executor(self, engine_paths: Dict[str, str] = None):
        """
        Initialize execution components

        Args:
            engine_paths: Dictionary of engine_type -> exe_path
        """
        self.executor = WorkflowExecutor(
            engine_paths=engine_paths,
            results_db_path=None  # Uses default ~/.emds/results.db
        )
        self.results_manager = ResultsManager()
        self.active_execution: Optional[str] = None
        self.progress_dialog: Optional[ExecutionProgressDialog] = None

        # Connect executor signals
        self.executor.execution_started.connect(self._on_execution_started)
        self.executor.execution_completed.connect(self._on_execution_completed)
        self.executor.execution_failed.connect(self._on_execution_failed)

    def add_execute_button(self):
        """Add Execute button to button layout"""
        self.btn_execute = QPushButton("Run Task")
        self.btn_execute.setEnabled(False)
        self.btn_execute.clicked.connect(self._execute_selected_workflow)
        self.button_layout.addWidget(self.btn_execute)

    def add_history_button(self):
        """Add View History button to button layout"""
        self.btn_history = QPushButton("View Task History")
        self.btn_history.setEnabled(False)
        self.btn_history.clicked.connect(self._show_execution_history)
        self.button_layout.addWidget(self.btn_history)

    def update_execution_button_state(self):
        """Update availability of execution buttons based on selection"""
        is_workflow_step = (
            self.selected_path and
            self.selected_path.get("workflow_step_id") is not None
        )

        if hasattr(self, 'btn_execute'):
            self.btn_execute.setEnabled(is_workflow_step and not self.active_execution)

        if hasattr(self, 'btn_history'):
            self.btn_history.setEnabled(is_workflow_step)

    def _execute_selected_workflow(self):
        """Execute selected workflow step"""
        if not self.selected_path or not self.selected_path.get("workflow_step_id"):
            QMessageBox.warning(self, "Error", "Please select a task to run")
            return

        # Get workflow step from project manager
        project_manager: ProjectManager = self.project_manager
        workflow_step = project_manager.find_workflow_step(
            self.selected_path["workflow_step_id"]
        )

        if not workflow_step:
            QMessageBox.warning(self, "Error", "Task not found")
            return

        # TODO: Get input layer data from selected layer in QGIS
        # For now, create dummy data
        try:
            input_data = pd.DataFrame({
                'column1': [1.0, 2.0, 3.0],
                'column2': [4.0, 5.0, 6.0],
            })

            # Start execution
            self.active_execution = self.executor.execute_workflow_step(
                workflow_step=workflow_step,
                input_layer_data=input_data
            )

            # Show progress dialog
            self.progress_dialog = ExecutionProgressDialog(workflow_step, self)
            self.progress_dialog.set_execution_id(self.active_execution)

            # Connect progress signals
            progress_signals = self.executor.get_execution_progress_signals(self.active_execution)
            if progress_signals:
                progress_signals.progress_updated.connect(
                    self.progress_dialog.update_progress
                )

            # Show dialog (non-blocking)
            self.progress_dialog.show()

        except Exception as e:
            QMessageBox.critical(self, "Error", f"Failed to start execution: {str(e)}")
            self.active_execution = None

    def _on_execution_started(self, execution_id: str):
        """Handle execution start"""
        self.active_execution = execution_id
        self.update_execution_button_state()

    def _on_execution_completed(self, execution_id: str, result: dict):
        """Handle execution completion"""
        self.active_execution = None
        self.update_execution_button_state()

        # Hide progress dialog
        if self.progress_dialog:
            self.progress_dialog.accept()
            self.progress_dialog = None

        # Get and display results
        results_df = self.executor.get_results(execution_id)

        viewer = ResultsViewerDialog(execution_id, results_df, self)
        exec_dialog(viewer)

        QMessageBox.information(
            self,
            "Task Complete",
            f"Task execution completed successfully.\n"
            f"Execution ID: {execution_id}\n"
            f"Rows processed: {result.get('rows_processed', 0)}"
        )

    def _on_execution_failed(self, execution_id: str, error_message: str):
        """Handle execution failure"""
        self.active_execution = None
        self.update_execution_button_state()

        # Hide progress dialog
        if self.progress_dialog:
            self.progress_dialog.reject()
            self.progress_dialog = None

        QMessageBox.critical(
            self,
            "Task Failed",
            f"Task execution failed:\n\n{error_message}"
        )

    def _show_execution_history(self):
        """Show execution history for selected workflow step"""
        if not self.selected_path or not self.selected_path.get("workflow_step_id"):
            QMessageBox.warning(self, "Error", "Please select a task")
            return

        workflow_step_id = self.selected_path["workflow_step_id"]

        history_dialog = ExecutionHistoryDialog(
            workflow_step_id,
            self.results_manager,
            self
        )
        exec_dialog(history_dialog)
