import time
import os
from PyQt5 import QtWidgets
from PyQt5.QtCore import QThread, pyqtSignal, QObject
from PyQt5.QtWidgets import QFileDialog
from main import get_discrete_data, get_raw_data
from utils.files.output import save_output_file, format_data
from utils.files.input import ScannedObject
from utils.math.position_manipulation import verticalise
from utils.gui.pyqt.main_window.UI_MainWindow import Ui_MainWindow

def analyse(file_path:str,output_path:str, output_file_prefix:str, delta_z:float,set_status,update_ui,set_weight):
    """
    Run the analyse

    Args:
        file_path (str): Path to the file to analyse
        output_path (str): Path to the output folder
        delta_z (float): Delta z to use
        set_status (function): Function to set the status
        update_ui (function): Function to update the ui
        set_weight (function): Function to set the weight   

    """
    set_status("Loading file...")
    obj = ScannedObject.from_obj_file(file_path)
    update_ui(5)
    set_status("Verticalising object...")
    verticalise(obj)
    update_ui(5)
    set_status("Normalising object...")
    obj.normalise()
    update_ui(5)
    set_weight(70)
    set_status("Calculating raw data...")
    raw_data = get_raw_data(obj, 6,delta_z,update_ui)
    set_status("Calculating discrete data...")
    discrete_data = get_discrete_data(obj, 6,delta_z,update_ui)
    set_weight(100)
    set_status("Saving data...")
    save_output_file(f'{output_path}/{output_file_prefix}_delta_{delta_z}_analyse_brute.txt',
                                format_data(raw_data,
                                            '\t',
                                            ["X (en mm)",
                                            "Y (en mm)",
                                            "Z (en mm)",
                                            "teta (en rad)",
                                            "rayon (en mm)",
                                            "Xi-Xmoy",
                                            "Yi-Ymoy"] ))
    update_ui(10)
    save_output_file(f'{output_path}/{output_file_prefix}_delta_{delta_z}_analyse_rayon.txt',
                                format_data(discrete_data,
                                        '\t',
                                        ["X moy (en mm)",
                                        "Y moy (en mm)",
                                        "Z moy (en mm)",
                                        "Delta z(en mm)",
                                        "Rayon moyen (en mm)",
                                        "Rayon ecart type (en mm)"] ))
    update_ui(100)
    set_status("Done !")

class Worker(QObject):
    """
    Worker to run the analyse in a thread
    """
    finished = pyqtSignal()
    progress = pyqtSignal(int)
    status = pyqtSignal(str)

    def __init__(self, objpath,output_path,output_file_prefix,delta_z):
        super().__init__()
        self.objpath = objpath
        self.delta_z = delta_z
        self.output_path = output_path
        self.output_file_prefix = output_file_prefix
        self.progress_value = 0
        self.progress_weight = 100

    def run(self):
        """
        Run the analyse
        """
        analyse(self.objpath,
                self.output_path,
                self.output_file_prefix,
                self.delta_z,
                self.set_status,
                self.update_progress,
                self.set_weight)
        
        self.finished.emit()

    def set_status(self, status:str):
        """
        Set the weight of the progress bar
        """
        self.status.emit(status)

    def set_weight(self, weight):
        """
        Set the weight of the progress bar
        """
        self.progress_weight = weight

    def update_progress(self, percent):
        """
        Update the progress bar
        """
        self.progress_value += int(percent/100*self.progress_weight)
        self.progress.emit(self.progress_value)

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    """
    Main window of the application
    """

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        # Retrieve the UI
        self.setupUi(self)
        # Setup buttons listeners
        self.start_analyse_button.clicked.connect(self.start_analyse)
        self.input_file_choose_btn.clicked.connect(self.select_file)
        self.output_folder_choose_btn.clicked.connect(self.select_folder)

        self.completed = 0

    def select_file(self):
        """
        Open a file dialog to select the input file
        """
        file = QFileDialog.getOpenFileName()[0]
        self.input_file_path.setPlainText(file)
        self.output_file_prefix.setText(os.path.splitext(os.path.basename(file))[0])

    def select_folder(self):
        """
        Open a file dialog to select the output folder
        """
        self.output_folder_path.setPlainText(
            QFileDialog.getExistingDirectory())

    def start_analyse(self):
        """
        Start the analyse
        """
        if not self.check_input_file():
            self.input_file_path.setPlainText("Invalid file path")
            return
        if not self.check_output_folder():
            self.output_folder_path.setPlainText("Invalid folder path")
            return

        # Create the thread to run the analyse
        self.thread = QThread()
        self.worker = Worker(self.input_file_path.toPlainText(),
                             self.output_folder_path.toPlainText(),
                             self.output_file_prefix.text(),
                             self.discretisation_value_selector.value())
        self.worker.moveToThread(self.thread)

        # Connect the signals
        # Start
        self.thread.started.connect(self.worker.run)
        # Progress
        self.worker.progress.connect(self.update_progress_bar)
        self.worker.status.connect(self.set_status)
        # Finished
        self.worker.finished.connect(self.finish_analyse)
        self.worker.finished.connect(self.thread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.thread.finished.connect(self.thread.deleteLater)

        # Start the thread
        self.thread.start()
        self.start_analyse_button.setEnabled(False)

    def set_status(self, status:str):
        """
        Set the status of the analyse
        """
        self.status_text.setText(status)

    def finish_analyse(self):
        """
        Finish the analyse
        """
        self.start_analyse_button.setEnabled(True)

    def check_input_file(self):
        """
        Check if the input file is valid
        """
        if os.path.isfile(self.input_file_path.toPlainText()):
            return True

    def check_output_folder(self):
        """
        Check if the output folder is valid
        """
        if os.path.isdir(self.output_folder_path.toPlainText()):
            return True

    def update_progress_bar(self, value):
        """
        Update the progress bar
        """
        self.analyse_progress_bar.setValue(value)