import os

from PySide6.QtCore import Qt
from PySide6.QtWidgets import QDialog, QFileDialog, QMessageBox

from conf import app_settings
from ui.PdfProject_ui import Ui_projectDlg
from ui.ProjectXsltParamsDialog import ProjectXsltParamsDialog


class PdfProjectDlg(QDialog):
    def __init__(self, parent=None, project_data=None, edit_mode=False):
        """
        Konstruktor für den PDF-Projekt-Dialog.
        
        Args:
            parent: Übergeordnetes Widget
            project_data: Bestehende Projektdaten zum Bearbeiten (optional)
            edit_mode: Wenn True, wird der Projekt-Ordner deaktiviert (nur Name und Einstellungen ändern)
        """
        super().__init__(parent)
        
        # UI einrichten
        self.ui = Ui_projectDlg()
        self.ui.setupUi(self)
        
        # Projektdaten speichern
        self.project_data = project_data or {}
        self.edit_mode = edit_mode
        self.xslt_params: dict[str, str] = dict(self.project_data.get("xslt_params", {}))
        
        # Dialog-Eigenschaften setzen
        self.setModal(True)
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowType.WindowContextHelpButtonHint)
        
        # Signale verbinden
        self._connect_signals()
        
        # ComboBoxen initialisieren
        self._init_combo_boxes()
        
        # Edit-Modus konfigurieren
        if self.edit_mode:
            self._configure_edit_mode()
        
        # Bestehende Projektdaten laden, falls vorhanden
        if self.project_data:
            self._load_project_data()
    
    def _connect_signals(self):
        """Verbindet die Signale mit den entsprechenden Slots."""
        # Browse-Button für Projekt-Ordner
        self.ui.pushButton.clicked.connect(self.browse_project_dir)

        # Browse-Button für FOP-Config-Ordner
        self.ui.btnBrowseFopConfig.clicked.connect(self.browse_fop_config_dir)

        # XSLT-Parameter bearbeiten
        self.ui.btnEditXsltParams.clicked.connect(self._edit_xslt_params)

        # OK/Cancel Buttons sind bereits in der UI-Datei verbunden
        # self.ui.buttonBox.accepted.connect(self.accept)
        # self.ui.buttonBox.rejected.connect(self.reject)

        # Überschreibe accept() für Validierung
        self.ui.buttonBox.accepted.disconnect()
        self.ui.buttonBox.accepted.connect(self.validate_and_accept)
    
    def _init_combo_boxes(self):
        """Initialisiert die ComboBoxen mit Werten aus app_settings."""
        # XSL-Ordner ComboBox
        self.ui.cB_XslDir.clear()
        for xsl_dir in app_settings.xsl_dirs:
            self.ui.cB_XslDir.addItem(xsl_dir.name, xsl_dir.id)
        if not app_settings.xsl_dirs:
            self.ui.cB_XslDir.addItem("Keine XSL-Ordner konfiguriert", -1)
        
        # Java VM ComboBox
        self.ui.cB_JavaVm.clear()
        for java_vm in app_settings.java_vms:
            self.ui.cB_JavaVm.addItem(java_vm.version, java_vm.id)
        if not app_settings.java_vms:
            self.ui.cB_JavaVm.addItem("Keine Java VMs konfiguriert", -1)
        
        # Saxon Jar ComboBox
        self.ui.cB_SaxonJar.clear()
        for saxon_jar in app_settings.saxon_jars:
            self.ui.cB_SaxonJar.addItem(saxon_jar.version, saxon_jar.id)
        if not app_settings.saxon_jars:
            self.ui.cB_SaxonJar.addItem("Keine Saxon JARs konfiguriert", -1)
        
        # Apache FOP ComboBox
        self.ui.cB_ApacheFop.clear()
        for apache_fop in app_settings.apache_fops:
            self.ui.cB_ApacheFop.addItem(apache_fop.version, apache_fop.id)
        if not app_settings.apache_fops:
            self.ui.cB_ApacheFop.addItem("Keine Apache FOP-Instanzen konfiguriert", -1)
        
        # diff-pdf ComboBox
        self.ui.cB_Diff_Pdf.clear()
        for postgres_db in app_settings.diff_pdfs:
            self.ui.cB_Diff_Pdf.addItem(postgres_db.version, postgres_db.id)
        if not app_settings.diff_pdfs:
            self.ui.cB_Diff_Pdf.addItem("Keine diff-pdf-Instanzen konfiguriert", -1)
        
        # Postgres ComboBox
        self.ui.cB_Postgres.clear()
        for postgres_db in app_settings.postgresql_dbs:
            self.ui.cB_Postgres.addItem(postgres_db.name, postgres_db.id)
        if not app_settings.postgresql_dbs:
            self.ui.cB_Postgres.addItem("Keine Postgres-Datenbanken konfiguriert", -1)
    
    def _load_project_data(self):
        """Lädt bestehende Projektdaten in die Eingabefelder."""
        # Projekt-Name
        if 'name' in self.project_data:
            self.ui.lineProjectName.setText(self.project_data['name'])
        
        # Projekt-Ordner
        if 'project_dir' in self.project_data:
            self.ui.lineProjectDir.setText(str(self.project_data['project_dir']))
        elif 'directory' in self.project_data:
            self.ui.lineProjectDir.setText(self.project_data['directory'])
        
        # ComboBox-Werte basierend auf IDs
        if 'xsl_dir_id' in self.project_data:
            self._select_combo_by_data(self.ui.cB_XslDir, self.project_data['xsl_dir_id'])
        
        if 'java_vm_id' in self.project_data:
            self._select_combo_by_data(self.ui.cB_JavaVm, self.project_data['java_vm_id'])
        
        if 'saxon_jar_id' in self.project_data:
            self._select_combo_by_data(self.ui.cB_SaxonJar, self.project_data['saxon_jar_id'])
        
        if 'apache_fop_id' in self.project_data:
            self._select_combo_by_data(self.ui.cB_ApacheFop, self.project_data['apache_fop_id'])
        
        if 'diff_pdf_id' in self.project_data:
            self._select_combo_by_data(self.ui.cB_Diff_Pdf, self.project_data['diff_pdf_id'])
        
        if 'postgre_sql_db_id' in self.project_data:
            self._select_combo_by_data(self.ui.cB_Postgres, self.project_data['postgre_sql_db_id'])

        # FOP-Config-Ordner
        if 'fop_config_dir' in self.project_data and self.project_data['fop_config_dir']:
            self.ui.lineFopConfigDir.setText(str(self.project_data['fop_config_dir']))
    
    def _select_combo_by_data(self, combo_box, data_value):
        """
        Wählt einen ComboBox-Eintrag basierend auf dem data-Wert aus.
        
        Args:
            combo_box: Die ComboBox
            data_value: Der zu suchende data-Wert
        """
        for i in range(combo_box.count()):
            if combo_box.itemData(i) == data_value:
                combo_box.setCurrentIndex(i)
                break
    
    def browse_project_dir(self):
        """Öffnet einen Dialog zum Auswählen des Projekt-Ordners."""
        current_dir = self.ui.lineProjectDir.text()
        if not current_dir or not os.path.exists(current_dir):
            current_dir = os.path.expanduser("~")
        
        selected_dir = QFileDialog.getExistingDirectory(
            self,
            "Projekt-Ordner auswählen",
            current_dir,
            QFileDialog.Option.ShowDirsOnly | QFileDialog.Option.DontResolveSymlinks
        )
        
        if selected_dir:
            self.ui.lineProjectDir.setText(selected_dir)
            
            # Automatisch Projekt-Name generieren, wenn leer
            if not self.ui.lineProjectName.text():
                project_name = os.path.basename(selected_dir)
                self.ui.lineProjectName.setText(project_name)

    def browse_fop_config_dir(self):
        """Öffnet einen Dialog zum Auswählen des FOP-Config-Ordners."""
        current_dir = self.ui.lineFopConfigDir.text()
        if not current_dir or not os.path.exists(current_dir):
            current_dir = os.path.expanduser("~")

        selected_dir = QFileDialog.getExistingDirectory(
            self,
            "FOP-Config-Ordner auswählen",
            current_dir,
            QFileDialog.Option.ShowDirsOnly | QFileDialog.Option.DontResolveSymlinks
        )

        if selected_dir:
            self.ui.lineFopConfigDir.setText(selected_dir)

    def _edit_xslt_params(self):
        """Öffnet den Dialog zur Bearbeitung der projektweiten XSLT-Parameter."""
        dialog = ProjectXsltParamsDialog(self, self.xslt_params)
        if dialog.exec() == ProjectXsltParamsDialog.DialogCode.Accepted:
            self.xslt_params = dialog.get_params()

    def validate_and_accept(self):
        """Validiert die Eingaben und akzeptiert den Dialog."""
        # Projekt-Name prüfen
        project_name = self.ui.lineProjectName.text().strip()
        if not project_name:
            QMessageBox.warning(
                self,
                "Ungültige Eingabe",
                "Bitte geben Sie einen Projekt-Namen ein."
            )
            self.ui.lineProjectName.setFocus()
            return
        
        # Projekt-Ordner prüfen
        project_dir = self.ui.lineProjectDir.text().strip()
        if not project_dir:
            QMessageBox.warning(
                self,
                "Ungültige Eingabe",
                "Bitte wählen Sie einen Projekt-Ordner aus."
            )
            self.ui.pushButton.setFocus()
            return
        
        # Prüfen, ob der Ordner existiert
        if not os.path.exists(project_dir):
            reply = QMessageBox.question(
                self,
                "Ordner nicht gefunden",
                f"Der Ordner '{project_dir}' existiert nicht.\n"
                "Möchten Sie ihn erstellen?",
                QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
                QMessageBox.StandardButton.No
            )
            
            if reply == QMessageBox.StandardButton.Yes:
                try:
                    os.makedirs(project_dir, exist_ok=True)
                except OSError as e:
                    QMessageBox.critical(
                        self,
                        "Fehler",
                        f"Der Ordner konnte nicht erstellt werden:\n{str(e)}"
                    )
                    return
            else:
                return
        
        # Prüfen, ob der Ordner beschreibbar ist
        if not os.access(project_dir, os.W_OK):
            QMessageBox.warning(
                self,
                "Ungültiger Ordner",
                f"Der Ordner '{project_dir}' ist nicht beschreibbar.\n"
                "Bitte wählen Sie einen anderen Ordner aus."
            )
            return
        
        
        # Alle Validierungen bestanden
        self.accept()
    
    def get_project_data(self):
        """
        Gibt die eingegebenen Projektdaten zurück.

        Returns:
            dict: Dictionary mit allen Projektdaten
        """
        fop_config_dir = self.ui.lineFopConfigDir.text().strip()
        return {
            'name': self.ui.lineProjectName.text().strip(),
            'project_dir': self.ui.lineProjectDir.text().strip(),
            'xsl_dir_id': self.ui.cB_XslDir.currentData(),
            'java_vm_id': self.ui.cB_JavaVm.currentData(),
            'saxon_jar_id': self.ui.cB_SaxonJar.currentData(),
            'apache_fop_id': self.ui.cB_ApacheFop.currentData(),
            'diff_pdf_id': self.ui.cB_Diff_Pdf.currentData(),
            'postgre_sql_db_id': self.ui.cB_Postgres.currentData(),
            'fop_config_dir': fop_config_dir if fop_config_dir else None,
            'xslt_params': self.xslt_params,
        }
    
    def _configure_edit_mode(self):
        """Konfiguriert den Dialog für den Edit-Modus (nur Einstellungen ändern)."""
        # Projekt-Ordner und Browse-Button deaktivieren
        self.ui.lineProjectDir.setEnabled(False)
        self.ui.pushButton.setEnabled(False)
        
        # Dialog-Titel ändern
        self.setWindowTitle("Projekt-Einstellungen bearbeiten")
    
    def set_project_data(self, project_data):
        """
        Setzt die Projektdaten in den Dialog.
        
        Args:
            project_data: Dictionary mit Projektdaten
        """
        self.project_data = project_data
        self._load_project_data()

