# -*- coding: utf-8 -*-
"""
/***************************************************************************
 AhpAnalysisDialog
                                 A QGIS plugin
 QGIS plugin for hierarchical multi-criteria analysis (AHP – Saaty method) using raster layers
                             -------------------
        begin                : 2025-12-20
        copyright            : (C) 2025 by Sewedo GNANSOUNOU
        email                : sewedo.gnansounou@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

import os
import re
import tempfile
import numpy as np

# ============================================================================
# UTILISER qgis.PyQt POUR LA COMPATIBILITÉ Qt5/Qt6
# ============================================================================
from qgis.PyQt import uic
from qgis.PyQt.QtWidgets import (QDialog, QTableWidgetItem, QComboBox,
                                  QMessageBox, QHeaderView, QLineEdit,
                                  QDoubleSpinBox, QLabel, QFileDialog)
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtGui import QColor
from qgis.core import QgsProject, QgsRasterLayer
from qgis.analysis import QgsRasterCalculator, QgsRasterCalculatorEntry
from .ahp_utils import calculate_weights, consistency_ratio
from .ahp_raster import (
    weighted_raster,
    check_raster_compatibility,
)

# ============================================================================
# COMPATIBILITÉ Qt5/Qt6 - FLAGS ET ENUMS
# ============================================================================
try:
    # Qt6
    ItemIsEditable = Qt.ItemFlag.ItemIsEditable
except AttributeError:
    # Qt5
    ItemIsEditable = Qt.ItemIsEditable

try:
    # Qt5
    _HeaderStretch = QHeaderView.Stretch
    _HeaderResizeToContents = QHeaderView.ResizeToContents
except AttributeError:
    # Qt6
    _HeaderStretch = QHeaderView.ResizeMode.Stretch
    _HeaderResizeToContents = QHeaderView.ResizeMode.ResizeToContents


# ============================================================================
# CHARGEMENT DU FICHIER .ui AVEC NORMALISATION DES ENUMS
# Le fichier .ui doit utiliser la syntaxe COURTE (sans namespace complet)
# car uic.loadUiType génère du code Python incorrect avec les namespaces Qt6
# ============================================================================
def load_ui_file(ui_filename):
    """
    Charge un fichier .ui en normalisant les enums Qt6 vers la syntaxe courte.
    
    Qt Designer Qt6 génère des enums comme:
      - Qt::AlignmentFlag::AlignCenter
      - Qt::Orientation::Vertical
      - QDialogButtonBox::StandardButton::Close
    
    Ces syntaxes causent des erreurs avec uic.loadUiType().
    On les convertit en syntaxe courte compatible Qt5/Qt6:
      - Qt::AlignCenter
      - Qt::Vertical
      - QDialogButtonBox::Close
    """
    ui_path = os.path.join(os.path.dirname(__file__), ui_filename)
    
    # Lire le contenu du fichier .ui
    with open(ui_path, 'r', encoding='utf-8') as f:
        ui_content = f.read()
    
    # Patterns de remplacement: syntaxe longue Qt6 → syntaxe courte
    replacements = [
        # Qt alignment flags
        (r'Qt::AlignmentFlag::(\w+)', r'Qt::\1'),
        # Qt orientation
        (r'Qt::Orientation::(\w+)', r'Qt::\1'),
        # Qt focus policy
        (r'Qt::FocusPolicy::(\w+)', r'Qt::\1'),
        # Qt layout direction
        (r'Qt::LayoutDirection::(\w+)', r'Qt::\1'),
        # Qt text flag
        (r'Qt::TextFlag::(\w+)', r'Qt::\1'),
        # Qt window flags
        (r'Qt::WindowType::(\w+)', r'Qt::\1'),
        # QDialogButtonBox standard buttons
        (r'QDialogButtonBox::StandardButton::(\w+)', r'QDialogButtonBox::\1'),
        # QSizePolicy
        (r'QSizePolicy::Policy::(\w+)', r'QSizePolicy::\1'),
        # QFrame
        (r'QFrame::Shape::(\w+)', r'QFrame::\1'),
        (r'QFrame::Shadow::(\w+)', r'QFrame::\1'),
        # QAbstractItemView
        (r'QAbstractItemView::SelectionMode::(\w+)', r'QAbstractItemView::\1'),
        (r'QAbstractItemView::SelectionBehavior::(\w+)', r'QAbstractItemView::\1'),
        # QHeaderView
        (r'QHeaderView::ResizeMode::(\w+)', r'QHeaderView::\1'),
        # QTabWidget
        (r'QTabWidget::TabPosition::(\w+)', r'QTabWidget::\1'),
        # QLineEdit
        (r'QLineEdit::EchoMode::(\w+)', r'QLineEdit::\1'),
    ]
    
    # Appliquer les remplacements avec regex
    for pattern, replacement in replacements:
        ui_content = re.sub(pattern, replacement, ui_content)
    
    # Créer un fichier temporaire avec le contenu normalisé
    temp_dir = tempfile.gettempdir()
    temp_ui_path = os.path.join(temp_dir, 'ahp_dialog_compat.ui')
    
    with open(temp_ui_path, 'w', encoding='utf-8') as f:
        f.write(ui_content)
    
    # Charger le fichier .ui normalisé via qgis.PyQt.uic
    return uic.loadUiType(temp_ui_path)


# Chargement du fichier .ui avec compatibilité Qt5/Qt6
FORM_CLASS, _ = load_ui_file('ahp_analysis_dialog_base.ui')


class AhpAnalysisDialog(QDialog, FORM_CLASS):
    """Dialogue principal pour l'analyse AHP."""

    def __init__(self, parent=None):
        """Constructeur."""
        super(AhpAnalysisDialog, self).__init__(parent)
        self.setupUi(self)

        # Initialisation des variables
        self.criteria = []  # Liste des critères définis
        self.criteria_validated = False  # Flag de validation
        self.raster_assignments = {}  # {criterion: {'layer': QgsRasterLayer, 'type': 'Benefit/Cost'}}
        self.reference_raster = None  # Premier raster sélectionné (référence)
        self.pairwise_matrix = None  # Matrice numpy de comparaison
        self.weights = None  # Poids calculés
        self.cr_value = None  # Ratio de cohérence

        # Connexion des signaux
        self._connect_signals()

        # Initialisation de l'interface
        self._init_ui()

    def _connect_signals(self):
        """Connexion des signaux aux slots."""
        # Page 1 - Critères
        self.addCriterionBtn.clicked.connect(self._add_criterion)
        self.removeCriterionBtn.clicked.connect(self._remove_criterion)
        self.clearCriteriaBtn.clicked.connect(self._clear_criteria)
        self.validateCriteriaBtn.clicked.connect(self._validate_criteria)

        # Navigation
        self.previousBtn.clicked.connect(self._previous_page)
        self.nextBtn.clicked.connect(self._next_page)

        # Page 4 - Génération
        self.generateRasterBtn.clicked.connect(self._generate_final_raster)

    def _init_ui(self):
        """Initialisation de l'interface utilisateur."""
        self.stackedWidget.setCurrentIndex(0)

        self.criteriaTable.horizontalHeader().setStretchLastSection(True)

        self.criteria_validated = False

        self._update_navigation_buttons()


    # ========================================================================
    # PAGE 1: DÉFINITION DES CRITÈRES
    # ========================================================================

    def _add_criterion(self):
        """Ajouter une nouvelle ligne pour un critère."""
        if self.criteria_validated:
            QMessageBox.warning(
                self,
                self.tr("Critères validés"),
                self.tr("Les critères ont déjà été validés. Vous ne pouvez plus les modifier.")
            )
            return

        row_count = self.criteriaTable.rowCount()
        self.criteriaTable.insertRow(row_count)

        # Cellule éditable pour le nom du critère
        item = QTableWidgetItem("")
        self.criteriaTable.setItem(row_count, 0, item)

    def _remove_criterion(self):
        """Supprimer la ligne sélectionnée."""
        if self.criteria_validated:
            QMessageBox.warning(
                self,
                self.tr("Critères validés"),
                self.tr("Les critères ont déjà été validés. Vous ne pouvez plus les modifier.")
            )
            return

        current_row = self.criteriaTable.currentRow()
        if current_row >= 0:
            self.criteriaTable.removeRow(current_row)

    def _clear_criteria(self):
        """Effacer tous les critères."""
        if self.criteria_validated:
            QMessageBox.warning(
                self,
                self.tr("Critères validés"),
                self.tr("Les critères ont déjà été validés. Vous ne pouvez plus les modifier.")
            )
            return

        self.criteriaTable.setRowCount(0)

    def _validate_criteria(self):
        """Valider les critères définis."""
        # Récupérer les critères
        criteria = []
        for row in range(self.criteriaTable.rowCount()):
            item = self.criteriaTable.item(row, 0)
            if item and item.text().strip():
                criterion_name = item.text().strip()
                if criterion_name in criteria:
                    self.page1StatusLabel.setText( self.tr(" Erreur : Critères dupliqués détectés."))
                    return
                criteria.append(criterion_name)

        # Validation
        if len(criteria) < 3:
            self.page1StatusLabel.setText( self.tr(" Veuillez définir au moins 3 critères."))
            return

        # Validation réussie
        self.criteria = criteria
        self.criteria_validated = True
        self.page1StatusLabel.setText(
            self.tr(" {count} critères validés avec succès.").format(count=len(criteria))
        )
        self.page1StatusLabel.setStyleSheet("color: green; font-weight: bold;")

        # Désactiver la table et les boutons
        self.criteriaTable.setEnabled(False)
        self.addCriterionBtn.setEnabled(False)
        self.removeCriterionBtn.setEnabled(False)
        self.clearCriteriaBtn.setEnabled(False)
        self.validateCriteriaBtn.setEnabled(False)

        # Activer la navigation vers la page 2
        self.nextBtn.setEnabled(True)

        # Préparer la page 2
        self._setup_page2()

    # ========================================================================
    # PAGE 2: ASSIGNATION DES RASTERS
    # ========================================================================

    def _setup_page2(self):
        """Préparer la table d'assignation des rasters."""
        self.rasterAssignmentTable.setRowCount(len(self.criteria))

        # Obtenir les couches raster du projet
        raster_layers = [layer for layer in QgsProject.instance().mapLayers().values()
                         if isinstance(layer, QgsRasterLayer)]

        for row, criterion in enumerate(self.criteria):
            # Colonne 0: Nom du critère (lecture seule)
            criterion_item = QTableWidgetItem(criterion)
            criterion_item.setFlags(criterion_item.flags() & ~ItemIsEditable)
            self.rasterAssignmentTable.setItem(row, 0, criterion_item)

            # Colonne 1: ComboBox pour sélectionner le raster
            raster_combo = QComboBox()
            raster_combo.addItem(self.tr("-- Sélectionner un raster --"), None)
            for layer in raster_layers:
                raster_combo.addItem(layer.name(), layer)
            raster_combo.currentIndexChanged.connect(
                lambda idx, r=row: self._on_raster_selected(r))
            self.rasterAssignmentTable.setCellWidget(row, 1, raster_combo)

            # Colonne 2: ComboBox pour le type (Benefit/Cost)
            type_combo = QComboBox()
            type_combo.addItem("Benefit")
            type_combo.addItem("Cost")
            self.rasterAssignmentTable.setCellWidget(row, 2, type_combo)

            # Colonne 3: Statut de compatibilité
            status_item = QTableWidgetItem(self.tr("⏳ En attente"))
            status_item.setFlags(status_item.flags() & ~ItemIsEditable)
            status_item.setBackground(QColor(220, 220, 220))
            self.rasterAssignmentTable.setItem(row, 3, status_item)

        # Ajuster les colonnes - Compatibilité Qt5/Qt6
        header = self.rasterAssignmentTable.horizontalHeader()
        header.setSectionResizeMode(0, _HeaderStretch)
        header.setSectionResizeMode(1, _HeaderStretch)
        header.setSectionResizeMode(2, _HeaderResizeToContents)
        header.setSectionResizeMode(3, _HeaderResizeToContents)

    def _on_raster_selected(self, row):
        """Callback lorsqu'un raster est sélectionné."""
        raster_combo = self.rasterAssignmentTable.cellWidget(row, 1)
        selected_layer = raster_combo.currentData()
        if selected_layer is None:
            status_item = self.rasterAssignmentTable.item(row, 3)
            status_item.setText(self.tr("⏳ En attente"))
            status_item.setBackground(QColor(220, 220, 220))

            # Supprimer l'assignation existante
            criterion = self.criteria[row]
            self.raster_assignments.pop(criterion, None)

            self._check_page2_completion()
            return

        selected_name = selected_layer.name()

        for c, data in self.raster_assignments.items():
            if data['layer'].name() == selected_name:
                QMessageBox.warning(
                    self,
                    self.tr("Raster déjà utilisé"),
                    self.tr(
                        "Le raster '{name}' est déjà associé à un autre critère.\n"
                        "Veuillez choisir un raster différent."
                    ).format(name=selected_name)
                )
                raster_combo.setCurrentIndex(0)
                return

        if selected_layer is None:
            # Réinitialiser le statut
            status_item = self.rasterAssignmentTable.item(row, 3)
            status_item.setText(self.tr("⏳ En attente"))
            status_item.setBackground(QColor(220, 220, 220))
            return

        # Vérifier la compatibilité spatiale

        if self.reference_raster is None:
            self.reference_raster = selected_layer
            is_compatible, message = True, "Premier raster défini comme référence."
        else:
            is_compatible, message = check_raster_compatibility(
                selected_layer,
                self.reference_raster
            )


        status_item = self.rasterAssignmentTable.item(row, 3)
        if is_compatible:
            status_item.setText(self.tr("✅ Compatible"))
            status_item.setBackground(QColor(144, 238, 144))  # Vert clair

            # Enregistrer l'assignation
            criterion = self.criteria[row]
            type_combo = self.rasterAssignmentTable.cellWidget(row, 2)
            self.raster_assignments[criterion] = {
                'layer': selected_layer,
                'type': type_combo.currentText()
            }
        else:
            status_item.setText(self.tr("❌ Incompatible"))
            status_item.setBackground(QColor(255, 182, 193))  # Rouge clair

            # Afficher message d'erreur détaillé
            QMessageBox.critical(self, self.tr("Incompatibilité raster"), message)

            # Réinitialiser la sélection
            raster_combo.setCurrentIndex(0)

        # Vérifier si tous les rasters sont assignés et compatibles
        self._check_page2_completion()


    def _check_page2_completion(self):
        """Vérifie si tous les rasters sont assignés et compatibles."""
        all_assigned = True

        for row in range(self.rasterAssignmentTable.rowCount()):
            status_item = self.rasterAssignmentTable.item(row, 3)
            if status_item is None or "✅" not in status_item.text():
                all_assigned = False
                break

        self._page2_completed = all_assigned

        #  ACTIVER LE BOUTON SUIVANT IMMÉDIATEMENT
        self.nextBtn.setEnabled(all_assigned)


    # ========================================================================
    # PAGE 3: MATRICE DE COMPARAISON PAIR-À-PAIR
    # ========================================================================

    def _setup_page3(self):
        """Préparer la matrice de comparaison pair-à-pair."""
        n = len(self.criteria)

        # Initialiser la matrice numpy
        self.pairwise_matrix = np.ones((n, n))

        # Configurer la table
        self.pairwiseMatrix.setRowCount(n)
        self.pairwiseMatrix.setColumnCount(n)

        # Définir les en-têtes
        self.pairwiseMatrix.setHorizontalHeaderLabels(self.criteria)
        self.pairwiseMatrix.setVerticalHeaderLabels(self.criteria)

        # Remplir la matrice
        for i in range(n):
            for j in range(n):
                if i == j:
                    # Diagonale: valeur = 1, non éditable
                    item = QTableWidgetItem("1.0")
                    item.setFlags(item.flags() & ~ItemIsEditable)
                    item.setBackground(QColor(200, 200, 200))
                    self.pairwiseMatrix.setItem(i, j, item)
                elif i < j:
                    # Partie supérieure: SpinBox éditable (échelle de Saaty)
                    spin = QDoubleSpinBox()
                    spin.setMinimum(1.0)
                    spin.setMaximum(9.0)
                    spin.setSingleStep(1.0)
                    spin.setValue(1.0)
                    spin.valueChanged.connect(lambda val, row=i, col=j: self._on_matrix_value_changed(row, col, val))
                    self.pairwiseMatrix.setCellWidget(i, j, spin)
                else:
                    # Partie inférieure: non éditable, calculée automatiquement
                    item = QTableWidgetItem("1.0")
                    item.setFlags(item.flags() & ~ItemIsEditable)
                    item.setBackground(QColor(240, 240, 240))
                    self.pairwiseMatrix.setItem(i, j, item)

        # Ajuster les colonnes
        self.pairwiseMatrix.resizeColumnsToContents()

        min_width = 120  # à ajuster selon ton UI

        for col in range(self.pairwiseMatrix.columnCount()):
            current = self.pairwiseMatrix.columnWidth(col)
            self.pairwiseMatrix.setColumnWidth(col, max(current, min_width))


    def _on_matrix_value_changed(self, row, col, value):
        """Callback lorsqu'une valeur de la matrice change."""
        # Mettre à jour la matrice numpy
        self.pairwise_matrix[row, col] = value

        # Calculer et afficher la valeur symétrique
        symmetric_value = 1.0 / value if value != 0 else 1.0
        self.pairwise_matrix[col, row] = symmetric_value

        # Mettre à jour l'affichage de la partie inférieure
        symmetric_item = self.pairwiseMatrix.item(col, row)
        if symmetric_item:
            symmetric_item.setText(f"{symmetric_value:.4f}")

        # Recalculer les poids et le CR
        self._calculate_ahp_weights()

    def _calculate_ahp_weights(self):
        """Calculer les poids AHP et le ratio de cohérence."""
        try:
            # Calculer les poids
            self.weights = calculate_weights(self.pairwise_matrix)

            # Calculer le CR
            self.cr_value = consistency_ratio(self.pairwise_matrix)

            # Afficher les poids
            weights_str = ", ".join([f"{w:.4f}" for w in self.weights])
            self.weightsValueLabel.setText(weights_str)

            # Afficher le CR
            self.crValueLabel.setText(f"{self.cr_value:.4f}")

            # Vérifier la cohérence
            if self.cr_value > 0.1:
                self.crValueLabel.setStyleSheet("color: red; font-weight: bold;")
                self.page3StatusLabel.setText(
                    self.tr(
                        " CR > 0.1 : La matrice n'est pas cohérente. Veuillez réviser vos comparaisons."
                    )
                )
                self.page3StatusLabel.setStyleSheet("color: red; font-weight: bold;")
                self._page3_completed = False

            else:
                self.crValueLabel.setStyleSheet("color: green; font-weight: bold;")
                self.page3StatusLabel.setText(
                    self.tr(" CR ≤ 0.1 : La matrice est cohérente.")
                )
                self.page3StatusLabel.setStyleSheet("color: green; font-weight: bold;")
                self._page3_completed = True
            #  Activation automatique du bouton Suivant
            self.nextBtn.setEnabled(self._page3_completed)

        except Exception as e:
            self.page3StatusLabel.setText(f" Erreur de calcul: {str(e)}")
            self._page3_completed = False
            self.nextBtn.setEnabled(False)


    def _check_page3_validity(self):
        """Vérifie que la matrice AHP est complète."""
        size = len(self.criteria)

        for i in range(size):
            for j in range(size):
                item = self.pairwiseMatrix.item(i, j)
                if item is None or not item.text():
                    self.page3NextButton.setEnabled(False)
                    return

        self.page3NextButton.setEnabled(True)
        self.pairwiseMatrix.itemChanged.connect(self._check_page3_validity)

    # ========================================================================
    # PAGE 4: GÉNÉRATION DU RASTER FINAL
    # ========================================================================

    def _setup_page4(self):
        """Préparer la page de génération du raster final."""
        # Afficher un résumé
        summary = self.tr("Résumé de l'analyse AHP:\n\n")

        summary += self.tr("Nombre de critères: {count}\n\n").format(
            count=len(self.criteria)
        )

        summary += self.tr("Critères et poids:\n")

        for i, criterion in enumerate(self.criteria):
            raster_name = self.raster_assignments[criterion]['layer'].name()
            raster_type = self.raster_assignments[criterion]['type']
            weight = self.weights[i]

            summary += self.tr(
                "  • {criterion} ({type}): {weight:.4f} → {raster}\n"
            ).format(
                criterion=criterion,
                type=raster_type,
                weight=weight,
                raster=raster_name
            )

        summary += self.tr(
            "\nRatio de cohérence (CR): {cr:.4f}\n"
        ).format(cr=self.cr_value)

        summary += self.tr("Prêt pour la génération du raster final.\n")

        self.summaryTextEdit.setText(summary)


    def _generate_final_raster(self):
        """Générer le raster final pondéré (QGIS natif)."""
        try:
            self.page4StatusLabel.setText(self.tr(" Génération en cours..."))
            self.page4StatusLabel.setStyleSheet("color: blue; font-weight: bold;")


            # Récupération des rasters et poids

            rasters = []
            weights_list = []

            for i, criterion in enumerate(self.criteria):
                rasters.append(self.raster_assignments[criterion]['layer'])
                weights_list.append(self.weights[i])


            # Choix du fichier de sortie (nom par défaut)

            default_name = "AHP_result.tif"

            output_path, _ = QFileDialog.getSaveFileName(
                self,
                self.tr("Enregistrer le raster AHP"),
                default_name,
                "GeoTIFF (*.tif)"
            )

            if not output_path:
                raise RuntimeError(self.tr("Aucun fichier de sortie sélectionné."))

            if not output_path.lower().endswith(".tif"):
                output_path += ".tif"


            # Calcul raster pondéré (QGIS raster calculator)



            output_layer = weighted_raster(
                rasters,
                weights_list,
                output_path=output_path,
                add_to_project=True
            )

            if output_layer and output_layer.isValid():
                self.page4StatusLabel.setText(self.tr("Raster final généré avec succès et ajouté au projet !"))
                self.page4StatusLabel.setStyleSheet("color: green; font-weight: bold;")

                QMessageBox.information(
                    self,
                    self.tr("Succès"),
                    self.tr(
                        "Le raster AHP a été généré avec succès:\n{path}"
                    ).format(path=output_path)
                )
            else:
                raise RuntimeError(self.tr("Raster de sortie invalide"))

        except Exception as e:
            self.page4StatusLabel.setText(f" Erreur : {str(e)}")
            self.page4StatusLabel.setStyleSheet("color: red; font-weight: bold;")

            QMessageBox.critical(
                self,
                self.tr("Erreur"),
                self.tr(
                    "Une erreur s'est produite lors de la génération du raster final :\n\n{error}"
                ).format(error=str(e))
            )


    # ========================================================================
    # NAVIGATION
    # ========================================================================

    def _next_page(self):
        current_index = self.stackedWidget.currentIndex()

        # Page 0 → Page 1 (info → critères) : AUCUNE condition
        if current_index == 1:  # Critères → Rasters
            if not self.criteria_validated:
                QMessageBox.warning(
                    self,
                    self.tr("Validation requise"),
                    self.tr("Veuillez valider les critères avant de continuer.")
                )
                return

        elif current_index == 2:  # Rasters → Matrice
            if not getattr(self, '_page2_completed', False):
                QMessageBox.warning(
                    self,
                    self.tr("Assignation incomplète"),
                    self.tr("Veuillez assigner un raster compatible à chaque critère.")
                )
                return
            self._setup_page3()

        elif current_index == 3:  # Matrice → Génération
            if not getattr(self, '_page3_completed', False):
                QMessageBox.warning(
                    self,
                    self.tr("Cohérence insuffisante"),
                    self.tr("Le ratio de cohérence (CR) doit être ≤ 0.1 pour continuer.")
                )
                return
            self._setup_page4()

        next_index = current_index + 1
        if next_index < self.stackedWidget.count():
            self.stackedWidget.setCurrentIndex(next_index)
            self._update_navigation_buttons()


    def _previous_page(self):
        """Retourner à la page précédente."""
        current_index = self.stackedWidget.currentIndex()
        if current_index > 0:
            self.stackedWidget.setCurrentIndex(current_index - 1)
            self._update_navigation_buttons()

    def _update_navigation_buttons(self):
        current_index = self.stackedWidget.currentIndex()

        # Bouton Précédent
        self.previousBtn.setEnabled(current_index > 0)

        # Bouton Suivant
        if current_index == 0:
            # PAGE 0 – Information
            self.nextBtn.setEnabled(True)

        elif current_index == 1:
            # PAGE 1 – Critères
            self.nextBtn.setEnabled(self.criteria_validated)

        elif current_index == 2:
            # PAGE 2 – Rasters
            self.nextBtn.setEnabled(
                hasattr(self, '_page2_completed') and self._page2_completed
            )

        elif current_index == 3:
            # PAGE 3 – Matrice AHP
            self.nextBtn.setEnabled(
                hasattr(self, '_page3_completed') and self._page3_completed
            )

        else:
            # PAGE 4 – Fin
            self.nextBtn.setEnabled(False)
