"""
Advanced Vectorization Parameters Dialog for QPredict

Provides a user interface to configure advanced parameters for the
professional vectorization pipeline (morphology, filtering, smoothing).

These parameters control the quality vs. performance trade-off when
converting raster predictions to vector polygons.
"""

from qgis.PyQt.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QFormLayout,
    QLabel, QSpinBox, QPushButton,
    QGroupBox, QComboBox, QDialogButtonBox
)
from qgis.PyQt.QtCore import Qt


class AdvancedVectorizationDialog(QDialog):
    """
    Dialog for configuring advanced vectorization parameters.
    
    Allows users to fine-tune the vectorization pipeline for different
    quality levels and use cases:
    - Fast: Optimized for speed (lower quality)
    - Balanced: Good trade-off (default)
    - Maximum: Best quality (slower)
    
    Parameters controlled:
    - morph_kernel_size: Morphological closing kernel (eliminate holes)
    - min_region_pixels: Minimum region size for filtering (noise removal)
    - chaikin_iterations: Chaikin smoothing iterations (curve smoothness)
    
    Note: simplify_tolerance is already in the main UI
    """
    
    # Quality presets
    PRESETS = {
        'Fast': {
            'morph_kernel_size': 2,
            'min_region_pixels': 16,
            'chaikin_iterations': 0,
            'description': 'Optimized for speed. Lower quality, faster processing.'
        },
        'Balanced': {
            'morph_kernel_size': 3,
            'min_region_pixels': 9,
            'chaikin_iterations': 1,
            'description': 'Good trade-off between quality and performance. Recommended for most use cases.'
        },
        'Maximum': {
            'morph_kernel_size': 5,
            'min_region_pixels': 4,
            'chaikin_iterations': 2,
            'description': 'Best quality. Slower processing, smooth organic shapes.'
        }
    }
    
    def __init__(self, parent=None, current_params=None):
        """
        Initialize advanced vectorization dialog.
        
        Args:
            parent: Parent widget
            current_params: Dict with current parameter values (optional)
        """
        super().__init__(parent)
        
        self.setWindowTitle("Advanced Vectorization Parameters")
        self.setModal(True)
        self.setMinimumWidth(500)
        
        # Store current parameters or use defaults
        self.params = current_params or self._get_default_params()
        
        self.init_ui()
        
        # Set initial values
        self._load_params(self.params)
    
    def _get_default_params(self):
        """Get default parameter values (Balanced preset)."""
        return {
            'morph_kernel_size': 3,
            'min_region_pixels': 9,
            'chaikin_iterations': 1
        }
    
    def init_ui(self):
        """Initialize the user interface."""
        layout = QVBoxLayout()
        layout.setSpacing(15)
        
        # ===================================================================
        # HEADER
        # ===================================================================
        header_label = QLabel(
            "Configure advanced parameters for vectorization pipeline.\n"
            "These settings control the quality vs. performance trade-off."
        )
        header_label.setWordWrap(True)
        header_label.setStyleSheet("color: gray; font-size: 10px;")
        layout.addWidget(header_label)
        
        # ===================================================================
        # QUALITY PRESETS
        # ===================================================================
        preset_group = QGroupBox("Quality Presets")
        preset_layout = QVBoxLayout()
        
        preset_select_layout = QHBoxLayout()
        preset_select_layout.addWidget(QLabel("Preset:"))
        
        self.preset_combo = QComboBox()
        self.preset_combo.addItems(list(self.PRESETS.keys()))
        self.preset_combo.setCurrentText('Balanced')
        self.preset_combo.currentTextChanged.connect(self.on_preset_changed)
        preset_select_layout.addWidget(self.preset_combo)
        preset_select_layout.addStretch()
        
        preset_layout.addLayout(preset_select_layout)
        
        # Preset description
        self.preset_desc_label = QLabel()
        self.preset_desc_label.setWordWrap(True)
        self.preset_desc_label.setStyleSheet(
            "color: #555; font-size: 9px; font-style: italic; padding: 5px;"
        )
        preset_layout.addWidget(self.preset_desc_label)
        
        preset_group.setLayout(preset_layout)
        layout.addWidget(preset_group)
        
        # ===================================================================
        # PARAMETERS
        # ===================================================================
        params_group = QGroupBox("Pipeline Parameters")
        params_layout = QFormLayout()
        params_layout.setSpacing(10)
        
        # Morphology kernel size
        morph_layout = QHBoxLayout()
        self.morph_spin = QSpinBox()
        self.morph_spin.setRange(0, 10)
        self.morph_spin.setSingleStep(1)
        self.morph_spin.setToolTip(
            "Morphological closing kernel size.\n\n"
            "Controls hole elimination and noise reduction:\n"
            "• 0 = No morphology (fastest, noisy)\n"
            "• 2-3 = Light cleaning (good for clean masks)\n"
            "• 4-5 = Aggressive cleaning (good for noisy masks)\n\n"
            "Higher values close larger holes but may over-smooth."
        )
        self.morph_spin.valueChanged.connect(self.on_param_changed)
        morph_layout.addWidget(self.morph_spin)
        morph_layout.addWidget(QLabel("kernel iterations"))
        morph_layout.addStretch()
        params_layout.addRow("Morphology Kernel:", morph_layout)
        
        # Min region pixels
        region_layout = QHBoxLayout()
        self.region_spin = QSpinBox()
        self.region_spin.setRange(1, 100)
        self.region_spin.setSingleStep(1)
        self.region_spin.setToolTip(
            "Minimum region size (in pixels) to keep.\n\n"
            "Filters small isolated regions:\n"
            "• 4 = Keep everything (2x2 pixels)\n"
            "• 9 = Balanced (3x3 pixels, recommended)\n"
            "• 16+ = Aggressive filtering (4x4+ pixels)\n\n"
            "Higher values remove more noise but may lose small objects."
        )
        self.region_spin.valueChanged.connect(self.on_param_changed)
        region_layout.addWidget(self.region_spin)
        region_layout.addWidget(QLabel("pixels"))
        region_layout.addStretch()
        params_layout.addRow("Min Region Size:", region_layout)
        
        # Chaikin iterations
        chaikin_layout = QHBoxLayout()
        self.chaikin_spin = QSpinBox()
        self.chaikin_spin.setRange(0, 3)
        self.chaikin_spin.setSingleStep(1)
        self.chaikin_spin.setToolTip(
            "Chaikin corner-cutting smoothing iterations.\n\n"
            "Controls curve smoothness:\n"
            "• 0 = No smoothing (angular edges)\n"
            "• 1 = Light smoothing (recommended, balanced)\n"
            "• 2 = Strong smoothing (organic shapes)\n"
            "• 3+ = Very smooth (may lose detail)\n\n"
            "Applied after simplification for smooth organic contours."
        )
        self.chaikin_spin.valueChanged.connect(self.on_param_changed)
        chaikin_layout.addWidget(self.chaikin_spin)
        chaikin_layout.addWidget(QLabel("iteration(s)"))
        chaikin_layout.addStretch()
        params_layout.addRow("Chaikin Smoothing:", chaikin_layout)
        
        params_group.setLayout(params_layout)
        layout.addWidget(params_group)
        
        # ===================================================================
        # INFO BOX
        # ===================================================================
        info_group = QGroupBox("ℹ️ Information")
        info_layout = QVBoxLayout()
        
        info_text = QLabel(
            "<b>Pipeline order:</b><br>"
            "1. Morphology (close holes)<br>"
            "2. Region filtering (remove noise)<br>"
            "3. Polygonization (rasterio)<br>"
            "4. Simplification (from main UI)<br>"
            "5. Chaikin smoothing (optional)<br><br>"
            "<b>Note:</b> Simplify Tolerance is configured in the main UI under Vector Layer options.\n"
            "It applies topology-aware simplification AFTER morphology and region filtering,\n"
            "and BEFORE Chaikin smoothing."
        )
        info_text.setWordWrap(True)
        info_text.setTextFormat(Qt.RichText)
        info_text.setStyleSheet("color: #555; font-size: 9px; padding: 5px;")
        info_layout.addWidget(info_text)
        
        info_group.setLayout(info_layout)
        layout.addWidget(info_group)
        
        # ===================================================================
        # BUTTONS
        # ===================================================================
        button_layout = QHBoxLayout()
        
        # Reset to defaults button
        self.reset_btn = QPushButton("Reset to Defaults")
        self.reset_btn.clicked.connect(self.on_reset_clicked)
        button_layout.addWidget(self.reset_btn)
        
        button_layout.addStretch()
        
        # OK/Cancel buttons
        self.button_box = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        )
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
        button_layout.addWidget(self.button_box)
        
        layout.addLayout(button_layout)
        
        # Set main layout
        self.setLayout(layout)
        
        # Update preset description
        self.on_preset_changed(self.preset_combo.currentText())
    
    def on_preset_changed(self, preset_name):
        """
        Handle preset selection change.
        
        Args:
            preset_name: Selected preset name ('Fast', 'Balanced', 'Maximum')
        """
        if preset_name not in self.PRESETS:
            return
        
        preset = self.PRESETS[preset_name]
        
        # Update description
        self.preset_desc_label.setText(preset['description'])
        
        # Update parameter values (block signals to avoid triggering on_param_changed)
        self.morph_spin.blockSignals(True)
        self.region_spin.blockSignals(True)
        self.chaikin_spin.blockSignals(True)
        
        self.morph_spin.setValue(preset['morph_kernel_size'])
        self.region_spin.setValue(preset['min_region_pixels'])
        self.chaikin_spin.setValue(preset['chaikin_iterations'])
        
        self.morph_spin.blockSignals(False)
        self.region_spin.blockSignals(False)
        self.chaikin_spin.blockSignals(False)
    
    def on_param_changed(self):
        """
        Handle manual parameter change.
        
        When user manually changes a parameter, reset preset to 'Custom'.
        """
        # Check if current values match any preset
        current = self.get_parameters()
        
        for preset_name, preset in self.PRESETS.items():
            if (current['morph_kernel_size'] == preset['morph_kernel_size'] and
                current['min_region_pixels'] == preset['min_region_pixels'] and
                current['chaikin_iterations'] == preset['chaikin_iterations']):
                # Values match a preset
                self.preset_combo.blockSignals(True)
                self.preset_combo.setCurrentText(preset_name)
                self.preset_combo.blockSignals(False)
                self.preset_desc_label.setText(preset['description'])
                return
        
        # Values don't match any preset → Custom
        self.preset_combo.blockSignals(True)
        if self.preset_combo.findText('Custom') == -1:
            self.preset_combo.addItem('Custom')
        self.preset_combo.setCurrentText('Custom')
        self.preset_combo.blockSignals(False)
        self.preset_desc_label.setText("Custom parameter values.")
    
    def on_reset_clicked(self):
        """Reset parameters to defaults (Balanced preset)."""
        self.preset_combo.setCurrentText('Balanced')
    
    def get_parameters(self):
        """
        Get current parameter values.
        
        Returns:
            dict: Parameter values
        """
        return {
            'morph_kernel_size': self.morph_spin.value(),
            'min_region_pixels': self.region_spin.value(),
            'chaikin_iterations': self.chaikin_spin.value()
        }
    
    def _load_params(self, params):
        """
        Load parameter values into UI.
        
        Args:
            params: Dict with parameter values
        """
        self.morph_spin.setValue(params.get('morph_kernel_size', 3))
        self.region_spin.setValue(params.get('min_region_pixels', 9))
        self.chaikin_spin.setValue(params.get('chaikin_iterations', 1))