import os
import json
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import (
    QWidget, QButtonGroup, QPushButton, QLabel, QGroupBox, QGridLayout, QTableWidget,
    QTableWidgetItem, QVBoxLayout, QHeaderView, QDialog, QFileDialog, QProgressDialog, QHBoxLayout,
    QLineEdit, QRadioButton, QCheckBox, QSizePolicy, QVBoxLayout
)
from PyQt5.QtGui import QFont  # Import QFont to change font size
from PyQt5.QtCore import Qt
from PyQt5.QtCore import pyqtSignal

class SettingsWindow(QDialog):
    data_updated = pyqtSignal()  # Signal emitted when data is updated

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Settings")
        self.resize(1200, 800)

        # Get the user's folder path (C:\Users\XXXXX)
        # This gets the user's home directory
        self.user_folder = os.path.expanduser("~")

        # Define the new folder "SEM" and the file to store settings
        self.new_folder = os.path.join(self.user_folder, "Raman")
        self.data_file = os.path.join(self.new_folder, "settings_data.json")
        
        # Set default settings file path
        self.default_settings_file = r'C:\Users\TM273821\PycharmProjects\Raman_sSOI_V2\RamanSOI\asset\Setting_Si.json'
        
        self.data = []  # Structure to store the table data
        self.input_values = []



        # Set up the UI layout
        self.layout = QHBoxLayout()  # Use QHBoxLayout for side-by-side layout
        self.setLayout(self.layout)

        # Create a container layout for the table and buttons (Vertical layout for table and buttons)
        self.table_layout = QVBoxLayout()

        # Create and add the table to the layout
        self.create_table()

        # Create the input fields section
        self.create_input_fields()

        # Create and add the buttons below the table
        self.create_buttons()

        # Load data from the settings file
        self.load_data()

        # Add the table layout to the main layout
        self.layout.addLayout(self.table_layout)

    def load_json_file(self):
        """Load settings from a JSON file and update settings window."""
        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getOpenFileName(self,
                                                   "Open JSON File",
                                                   "",
                                                   "JSON Files (*.json);;All Files (*)",
                                                   options=options)


        if file_path:
            try :
                with open(file_path, "r") as file:
                    saved_data = json.load(file)
                    print(saved_data)

                    # Réinitialiser la table et les données
                    self.table.setRowCount(0)  # Vider la table
                    self.data = []  # Réinitialiser la structure interne

                    table_data = saved_data.get("table_data", [])
                    for row_data in table_data:
                        self.add_row(
                            row_data.get("Peak", ""), row_data.get("Ylabel", ""),
                            row_data.get("Filename", ""), row_data.get("Min", ""),
                            row_data.get("Max", ""), row_data.get("Threshold", False),
                            row_data.get("Boxplot", False), update_data=False
                        )
                    self.data = table_data

                    # Charger les valeurs des champs d'entrée
                    self.input_values = saved_data.get("input_values")
                    self.wafer_size_input.setText(self.input_values.get("Wafer Size"))
                    self.edge_exclusion_input.setText(
                        self.input_values.get("Edge Exclusion"))
                    self.spectra_xmin_input.setText(
                        self.input_values.get("Spectra xmin"))
                    self.spectra_xmax_input.setText(
                        self.input_values.get("Spectra xmax"))
                    self.spectra_ymin_input.setText(
                        self.input_values.get("Spectra ymin"))
                    self.spectra_ymax_input.setText(
                        self.input_values.get("Spectra ymax"))
                    self.spectra_xlabel_input.setText(self.input_values.get("Xlabel"))
                    self.spectra_ylabel_input.setText(self.input_values.get("Ylabel"))

                    print("Data loaded successfully:", self.data, self.input_values)
            except FileNotFoundError:
                print("No previous data found. Starting fresh.")
                self.data = []
            except Exception as e:
                print(f"Error loading data: {e}")
                self.data = []

    def create_table(self):
        """Create the settings table."""
        self.table = QTableWidget()
        self.table.setColumnCount(7)  # Total 6 columns
        self.table.setHorizontalHeaderLabels(["Peak", "Ylabel", "Filename", "Min", "Max", "Threshold", "Boxplot"])
        self.table.setMinimumHeight(200)
        self.table.setMinimumWidth(800)

        self.table.blockSignals(True)

        # Appliquer un style pour augmenter la taille du texte
        self.table.setStyleSheet("""
               QTableWidget {
                   font-size: 16px;  /* Augmenter la taille du texte */
                   text-align: center;  /* Centrer le texte dans toutes les cellules */
               }
               QTableWidget::item {
                   padding: 5px;  /* Ajouter un peu de marge autour du texte */
                   text-align: center;  /* Centrer le texte dans les cellules */
               }
               QHeaderView::section {
                   font-size: 16px;  /* Taille du texte des en-têtes */
                   background-color: #f2f2f2;  /* Couleur de fond pour les en-têtes */
                   text-align: center;  /* Centrer le texte dans les en-têtes */
               }
           """)

        # Populate the table with existing data
        for row_data in self.data:
            self.add_row(
                row_data.get("Peak", ""), row_data.get("Ylabel", ""),
                row_data.get("Filename", ""), row_data.get("Min", ""),
                row_data.get("Max", ""), row_data.get("Threshold", False),
                row_data.get("Boxplot", False), update_data=False
            )

        self.table.blockSignals(False)
        self.table.itemChanged.connect(self.update_data)
        self.table_layout.addWidget(self.table)


    def remove_selected_row(self):
        """Remove the currently selected row."""
        current_row = self.table.currentRow()
        if current_row != -1:
            self.table.removeRow(current_row)
            del self.data[current_row]


    def create_buttons(self):
        """Create buttons to add and remove rows, and load JSON."""
        add_button = QPushButton("Add Row")
        remove_button = QPushButton("Remove Selected Row")
        load_button = QPushButton("Load JSON")
        save_button = QPushButton(
            "Save JSON File")

        button_style = """
                QPushButton {
                    font-size: 18px;  /* Augmenter la taille de la police */
                    background-color: #f0f0f0;  /* Fond gris clair */
                    color: black;  /* Texte noir */
                    border: 2px solid black;  /* Bordure noire */
                    border-radius: 10px;  /* Coins arrondis */
                    padding: 10px 20px;  /* Espacement interne */
                    min-width: 150px;  /* Largeur minimale pour chaque bouton */
                    transition: all 0.3s ease;  /* Transition douce pour les effets de survol */
                }

                QPushButton:hover {
                    background-color: #e0e0e0;  /* Fond gris légèrement plus foncé au survol */
                    border-color: black;  /* Bordure noire inchangée */
                }

                QPushButton:pressed {
                    background-color: #d0d0d0;  /* Fond gris encore plus foncé lorsqu'on appuie */
                    border-color: black;  /* Bordure noire inchangée */
                }
            """

        # Appliquer le style aux boutons
        add_button.setStyleSheet(button_style)
        remove_button.setStyleSheet(button_style)
        load_button.setStyleSheet(button_style)
        save_button.setStyleSheet(button_style)

        add_button.clicked.connect(self.add_row)
        remove_button.clicked.connect(self.remove_selected_row)
        load_button.clicked.connect(
            self.load_json_file)  # Connect load button to load_json_file
        save_button.clicked.connect(self.save_json_file)

        # Add buttons to the layout under the table
        self.table_layout.addWidget(add_button)
        self.table_layout.addWidget(remove_button)
        self.table_layout.addWidget(
            load_button)  # Add the load button to the layout
        self.table_layout.addWidget(
            save_button)  # Ajouter le bouton "Save" au layout

    def save_json_file(self):
        """Save settings to a JSON file."""
        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getSaveFileName(self,
                                                   "Save JSON File",
                                                   "",
                                                   "JSON Files (*.json);;All Files (*)",
                                                   options=options)
        if file_path:
            # Récupérer les valeurs des champs d'entrée
            input_values = {
                "Wafer Size": self.wafer_size_input.text(),
                "Edge Exclusion": self.edge_exclusion_input.text(),
                "Spectra xmin": self.spectra_xmin_input.text(),
                "Spectra xmax": self.spectra_xmax_input.text(),
                "Spectra ymin": self.spectra_ymin_input.text(),
                "Spectra ymax": self.spectra_ymax_input.text(),
                "Xlabel": self.spectra_xlabel_input.text(),
                "Ylabel": self.spectra_ylabel_input.text()
            }

            # Récupérer les données de la table
            table_data = []
            for row in range(self.table.rowCount()):
                # Récupérer les valeurs des colonnes de texte
                peak = self.table.item(row, 0).text() if self.table.item(row,
                                                                         0) else ""
                ylabel = self.table.item(row, 1).text() if self.table.item(row,
                                                                           1) else ""
                filename = self.table.item(row, 2).text() if self.table.item(
                    row, 2) else ""
                min_value = self.table.item(row, 3).text() if self.table.item(
                    row, 3) else ""
                max_value = self.table.item(row, 4).text() if self.table.item(
                    row, 4) else ""

                # Récupérer les états des cases à cocher
                threshold_checkbox = self.table.cellWidget(row, 5)
                boxplot_checkbox = self.table.cellWidget(row, 6)
                threshold_checked = threshold_checkbox.isChecked() if isinstance(
                    threshold_checkbox, QCheckBox) else False
                boxplot_checked = boxplot_checkbox.isChecked() if isinstance(
                    boxplot_checkbox, QCheckBox) else False

                # Ajouter une ligne complète au tableau de données
                table_data.append({
                    "Peak": peak,
                    "Ylabel": ylabel,
                    "Filename": filename,
                    "Min": min_value,
                    "Max": max_value,
                    "Threshold": threshold_checked,
                    "Boxplot": boxplot_checked
                })

            # Sauvegarder les données dans le fichier JSON
            data_to_save = {
                "table_data": table_data,
                "input_values": input_values
            }

            with open(file_path, 'w') as file:
                json.dump(data_to_save, file, indent=4)
            print("Data saved successfully:", data_to_save)

    def create_input_fields(self):
        """Create input fields for wafer size and spectra limits inside a QGroupBox."""
        # Créer un QGroupBox pour les champs d'entrée
        # Créer une fonction pour ajouter des lignes avec un label et un champ de texte alignés à droite

        self.input_group_box = QGroupBox("Input Fields")
        self.input_layout = QVBoxLayout()

        def create_input_row(label_text, input_widget):
            # Créer un QHBoxLayout pour aligner le label à gauche et le champ à droite
            row_layout = QHBoxLayout()

            # Créer le label
            label = QLabel(label_text)
            label.setStyleSheet("""
                    QLabel {
                        font-size: 18px;
                        color: black;  /* Texte noir */
                        margin-right: 10px;  /* Espacement à droite */
                    }
                """)

            # Créer le champ de texte
            input_widget.setStyleSheet("""
                    QLineEdit {
                        font-size: 18px;  /* Taille de la police plus grande */
                        color: black;  /* Texte noir */
                        padding: 10px;
                        min-width: 200px;  /* Largeur minimum pour les champs de texte */
                    }

                """)

            # Ajouter le label et le champ de texte au QHBoxLayout
            row_layout.addWidget(label)
            row_layout.addWidget(input_widget)

            return row_layout

        # Wafer Size Input
        self.wafer_size_input = QLineEdit()
        self.input_layout.addLayout(
            create_input_row("Wafer Size (cm):", self.wafer_size_input))

        # Edge exclusion Input
        self.edge_exclusion_input = QLineEdit()
        self.input_layout.addLayout(
            create_input_row("Edge Exclusion (cm):", self.edge_exclusion_input))

        # Spectra xmin, xmax, ymin, ymax Inputs
        self.spectra_xmin_input = QLineEdit()
        self.input_layout.addLayout(
            create_input_row("Spectra xmin:", self.spectra_xmin_input))

        self.spectra_xmax_input = QLineEdit()
        self.input_layout.addLayout(
            create_input_row("Spectra xmax:", self.spectra_xmax_input))

        self.spectra_ymin_input = QLineEdit()
        self.input_layout.addLayout(
            create_input_row("Spectra ymin:", self.spectra_ymin_input))

        self.spectra_ymax_input = QLineEdit()
        self.input_layout.addLayout(
            create_input_row("Spectra ymax:", self.spectra_ymax_input))

        self.spectra_xlabel_input = QLineEdit()
        self.input_layout.addLayout(
            create_input_row("Xlabel:", self.spectra_xlabel_input))

        self.spectra_ylabel_input = QLineEdit()
        self.input_layout.addLayout(
            create_input_row("Ylabel:", self.spectra_ylabel_input))

        # Associer le layout au QGroupBox
        self.input_group_box.setLayout(self.input_layout)

        # Ajouter le QGroupBox au layout principal
        self.layout.addWidget(self.input_group_box)

    def add_row(self, peak=None, ylabel="", filename="", min_value="",
                max_value="", is_checked=False, boxplot_checked=False,
                update_data=True):
        """Add a new row to the table with default values."""

        # Normalisation de la valeur 'peak'
        if peak in (None,
                    False):  # Traiter les valeurs None ou False comme des chaînes vides
            peak = ""

        row_position = self.table.rowCount()
        self.table.insertRow(row_position)

        # Créer les éléments pour chaque colonne
        peak_item = QTableWidgetItem(str(peak))
        ylabel_item = QTableWidgetItem(str(ylabel))
        filename_item = QTableWidgetItem(str(filename))
        min_item = QTableWidgetItem(str(min_value))
        max_item = QTableWidgetItem(str(max_value))

        # Ajouter les éléments dans la table
        self.table.setItem(row_position, 0, peak_item)
        self.table.setItem(row_position, 1, ylabel_item)
        self.table.setItem(row_position, 2, filename_item)
        self.table.setItem(row_position, 3, min_item)
        self.table.setItem(row_position, 4, max_item)

        # Ajouter la case à cocher dans la colonne "Threshold"
        checkbox = QCheckBox()
        checkbox.setChecked(bool(is_checked))  # Conversion explicite en booléen
        checkbox.stateChanged.connect(
            lambda state, row=row_position: self.handle_checkbox_state_change(
                state, row))
        self.table.setCellWidget(row_position, 5, checkbox)

        # Ajouter la case à cocher dans la colonne "Boxplot"
        boxplot_checkbox = QCheckBox()
        boxplot_checkbox.setChecked(
            bool(boxplot_checked))  # Conversion explicite en booléen
        boxplot_checkbox.stateChanged.connect(
            lambda state,
                   row=row_position: self.handle_boxplot_checkbox_state_change(
                state, row))
        self.table.setCellWidget(row_position, 6, boxplot_checkbox)

        # Mettre à jour la structure de données interne
        if update_data:
            self.data.append({
                "Peak": peak or "",
                "Ylabel": ylabel or "",
                "Filename": filename or "",
                "Min": min_value or "",
                "Max": max_value or "",
                "Threshold": bool(is_checked),  # S'assurer que c'est un booléen
                "Boxplot": bool(boxplot_checked),
                # S'assurer que c'est un booléen
            })

        self.table.itemChanged.connect(self.update_data)

        print(self.data)

    def handle_boxplot_checkbox_state_change(self, state, current_row):
        """Handle state change for the 'Boxplot' checkbox."""
        is_checked = state == Qt.Checked
        if current_row < len(self.data):
            self.data[current_row]["Boxplot"] = is_checked
            print(f"Boxplot updated for row {current_row}: {is_checked}")

    def handle_checkbox_state_change(self, state, current_row):
        """Ensure only one checkbox is selected at a time."""
        if state == Qt.Checked:
            for row in range(self.table.rowCount()):
                if row != current_row:
                    checkbox = self.table.cellWidget(row, 5)
                    checkbox.blockSignals(True)
                    checkbox.setChecked(False)
                    checkbox.blockSignals(False)

            # Update the data to reflect the single selection
            for i, row_data in enumerate(self.data):
                row_data["Threshold"] = (i == current_row)



    def remove_selected_row(self):
        """Remove the currently selected row from the table."""
        current_row = self.table.currentRow()
        if current_row != -1:
            self.table.removeRow(current_row)
            del self.data[current_row]  # Remove the corresponding data
            print("Row removed:", self.data)  # Debugging

    def update_data(self, item):
        """
        Update the data structure when a table cell value or input field value changes.
        """
        if isinstance(item, QTableWidgetItem):  # Si c'est un élément du tableau
            row = item.row()
            column = item.column()

            if row >= len(self.data):
                return  # Si la ligne n'existe pas dans `self.data`, ne rien faire

            # Mettre à jour la ligne correspondante dans `data`
            if column == 0:
                self.data[row]["Peak"] = item.text()
            elif column == 1:
                self.data[row]["Ylabel"] = item.text()
            elif column == 2:
                self.data[row]["Filename"] = item.text()
            elif column == 3:
                self.data[row]["Min"] = item.text()
            elif column == 4:
                self.data[row]["Max"] = item.text()

            # Afficher pour le débogage
            print(f"Table data updated: {self.data[row]}")

        elif isinstance(item, QLineEdit):  # Si c'est un champ d'entrée
            self.input_values = {
                "Wafer Size": self.wafer_size_input.text(),
                "Edge Exclusion": self.edge_exclusion_input.text(),
                "Spectra xmin": self.spectra_xmin_input.text(),
                "Spectra xmax": self.spectra_xmax_input.text(),
                "Spectra ymin": self.spectra_ymin_input.text(),
                "Spectra ymax": self.spectra_ymax_input.text(),
                "Xlabel": self.spectra_xlabel_input.text(),
                "Ylabel": self.spectra_ylabel_input.text(),
            }

            # Afficher pour le débogage
            print(f"Input fields updated: {self.input_values}")

            # Mettre à jour les colonnes Threshold et Boxplot
        for row in range(self.table.rowCount()):
            if row < len(self.data):
                threshold_checkbox = self.table.cellWidget(row, 5)
                boxplot_checkbox = self.table.cellWidget(row, 6)

                if isinstance(threshold_checkbox, QCheckBox):
                    self.data[row]["Threshold"] = threshold_checkbox.isChecked()
                if isinstance(boxplot_checkbox, QCheckBox):
                    self.data[row]["Boxplot"] = boxplot_checkbox.isChecked()

                # Afficher pour le débogage
                print(f"Checkbox data updated for row {row}: {self.data[row]}")

        # Sauvegarder les données mises à jour
        self.save_data()

        print(self.input_values)

    def closeEvent(self, event):
        """Save data to a file when the dialog is closed."""
        self.save_data()
        # Emit signal to indicate data has been updated
        self.data_updated.emit()
        # Call parent method to handle the close event
        super().closeEvent(event)

    def save_data(self):
        """Save the table data and input field values to a JSON file."""
        os.makedirs(os.path.dirname(self.data_file), exist_ok=True)

        # Récupérer les valeurs des champs d'entrée
        self.input_values = {
            "Wafer Size": self.wafer_size_input.text(),
            "Edge Exclusion": self.edge_exclusion_input.text(),
            "Spectra xmin": self.spectra_xmin_input.text(),
            "Spectra xmax": self.spectra_xmax_input.text(),
            "Spectra ymin": self.spectra_ymin_input.text(),
            "Spectra ymax": self.spectra_ymax_input.text(),
            "Xlabel": self.spectra_xlabel_input.text(),
            "Ylabel": self.spectra_ylabel_input.text()
        }

        # Sauvegarder à la fois les données du tableau et les valeurs des champs d'entrée
        data_to_save = {
            "table_data": self.data,  # Sauvegarder les lignes du tableau
            "input_values": self.input_values
            # Sauvegarder les valeurs des champs d'entrée
        }

        print(data_to_save)
        # Sauvegarder dans le fichier JSON
        try:
            with open(self.data_file, "w") as file:
                json.dump(data_to_save, file, indent=4)
            # print("Data saved successfully.")  # Debugging
        except Exception as e:
            print(f"Error saving data: {e}")


    def load_data(self):
        """Load the table data and input field values from the JSON file."""
        # Try to load from default settings file first
        settings_file = None
        if os.path.exists(self.default_settings_file):
            settings_file = self.default_settings_file
            print(f"Loading default settings from: {settings_file}")
        elif os.path.exists(self.data_file):
            settings_file = self.data_file
            print(f"Loading saved settings from: {settings_file}")
        
        if settings_file:
            try:
                with open(settings_file, "r") as file:
                    saved_data = json.load(file)
                    print(saved_data)
                    table_data = saved_data.get("table_data", [])
                    for row_data in table_data:
                        self.add_row(
                            row_data.get("Peak", ""), row_data.get("Ylabel", ""),
                            row_data.get("Filename", ""), row_data.get("Min", ""),
                            row_data.get("Max", ""), row_data.get("Threshold", False),
                            row_data.get("Boxplot", False), update_data=False
                        )
                    self.data = table_data

                    # Charger les valeurs des champs d'entrée
                    self.input_values = saved_data.get("input_values", {})
                    if self.input_values:
                        self.wafer_size_input.setText(self.input_values.get("Wafer Size", ""))
                        self.edge_exclusion_input.setText(self.input_values.get("Edge Exclusion", ""))
                        self.spectra_xmin_input.setText(self.input_values.get("Spectra xmin", ""))
                        self.spectra_xmax_input.setText(self.input_values.get("Spectra xmax", ""))
                        self.spectra_ymin_input.setText(self.input_values.get("Spectra ymin", ""))
                        self.spectra_ymax_input.setText(self.input_values.get("Spectra ymax", ""))
                        self.spectra_xlabel_input.setText(self.input_values.get("Xlabel", ""))
                        self.spectra_ylabel_input.setText(self.input_values.get("Ylabel", ""))

                print("Data loaded successfully:", self.data, self.input_values)
            except Exception as e:
                print(f"Error loading data: {e}")
                self.data = []
                self.input_values = {}
        else:
            print("No settings file found. Starting fresh.")
            self.data = []
            self.input_values = {}

    def get_table_data(self):
        """Get the current data from the table as a list of dictionaries."""
        if self.input_values is not None:
            print(f"Data : {self.data}")
            return self.data, self.input_values


if __name__ == "__main__":
    app = QApplication(sys.argv)
    settings_window = SettingsWindow()
    settings_window.show()
    sys.exit(app.exec_())

