import platform
if platform.system() == "Darwin":
    import UnnecessaryImportToPreventTheWidgetFromBeingDisplayedOnMacOS

import os
import sys
import whisper

import Orange.data
from Orange.data import StringVariable
from AnyQt.QtWidgets import QApplication
from Orange.widgets.settings import Setting
from Orange.widgets.utils.signals import Input, Output

import torch
from pyannote.audio import Audio
from speechbrain.inference.speaker import EncoderClassifier

if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
    from Orange.widgets.orangecontrib.IO4IT.utils import audio
    from Orange.widgets.orangecontrib.AAIT.utils import thread_management, base_widget
    from Orange.widgets.orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
    from Orange.widgets.orangecontrib.AAIT.utils.MetManagement import get_local_store_path
else:
    from orangecontrib.IO4IT.utils import audio
    from orangecontrib.AAIT.utils import thread_management, base_widget
    from orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
    from orangecontrib.AAIT.utils.MetManagement import get_local_store_path


@apply_modification_from_python_file(filepath_original_widget=__file__)
class OWSpeechToText(base_widget.BaseListWidget):
    name = "OWSpeechToText - toto "
    description = "Convert audio to text with speaker recognition"
    priority = 1111
    category = "Advanced Artificial Intelligence Tools"
    icon = "icons/speech_to_text.png"
    if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
        icon = "icons_dev/speech_to_text.png"
    gui = os.path.join(os.path.dirname(os.path.abspath(__file__)), "designer/owspeechtotext.ui")
    category = "AAIT - TOOLBOX"

    # Settings
    selected_column_name = Setting("content")

    class Inputs:
        data = Input("Data", Orange.data.Table)
        model = Input("Model", type=whisper.Whisper, auto_summary=False)

    class Outputs:
        data = Output("Data", Orange.data.Table)

    @Inputs.data
    def set_data(self, in_data):
        self.data = in_data
        if self.data:
            self.var_selector.add_variables(self.data.domain)
            self.var_selector.select_variable_by_name(self.selected_column_name)
        if self.autorun:
            self.run()

    @Inputs.model
    def set_model(self, in_model):
        self.model = in_model
        print("in_model", in_model)
        if self.autorun:
            self.run()

    def __init__(self):
        super().__init__()
        # Qt Management
        self.setFixedWidth(470)
        self.setFixedHeight(450)
        # uic.loadUi(self.gui, self)

        # Data Management
        self.data = None
        self.model = None
        self.thread = None
        self.autorun = True
        self.result = None
        self.post_initialized()

        self.local_store_path = get_local_store_path()
        model_name = "small.pt"
        self.embedding_model_name = "spkrec-ecapa-voxceleb"
        self.model_path = os.path.join(self.local_store_path, "Models", "S2T", model_name)
        self.embedding_model_path = os.path.join(self.local_store_path, "Models", "S2T", self.embedding_model_name)

        self.ffmpeg_path = os.path.join(self.local_store_path, "Models", "S2T", "ffmpeg", "bin", "ffmpeg.exe")
        # Extraire le dossier de ffmpeg.exe
        ffmpeg_bin_dir = os.path.dirname(self.ffmpeg_path)

        # Ajouter ffmpeg au PATH pour whisper/ffmpeg-python
        if ffmpeg_bin_dir not in os.environ["PATH"]:
            os.environ["PATH"] = ffmpeg_bin_dir + os.pathsep + os.environ["PATH"]
            print(f"[INFO] Dossier ffmpeg ajouté au PATH Python : {ffmpeg_bin_dir}")

        # Note: Dans un environnement Orange réel, vous devriez vérifier si le modèle
        # a été correctement téléchargé et chargé avant de continuer.
        try:
            self.model = whisper.load_model("small", device="cuda" if torch.cuda.is_available() else "cpu")
            self.device = next(self.model.parameters()).device
        except Exception:
            self.model = None
            self.device = "cpu"

        try:
            self.embedding_model = EncoderClassifier.from_hparams(
                source=self.embedding_model_path,
                run_opts={"device": self.device}
            )
        except Exception:
            self.embedding_model = None

        self.audio_helper = Audio()

    def run(self):
        self.error("")
        self.warning("")

        # Vérification des modèles critiques avant de lancer le thread
        if self.embedding_model is None or self.audio_helper is None:
            self.error(
                "Les modèles de diarisation (SpeechBrain/Pyannote) n'ont pas pu être chargés. Veuillez vérifier les chemins.")
            self.Outputs.data.send(None)
            return

        # if thread is running quit
        if self.thread is not None:
            self.thread.safe_quit()

        if self.data is None:
            self.Outputs.data.send(None)
            return

        if self.model is None:
            print("model is none")
            self.Outputs.data.send(None)
            return

        # Verification of in_data
        if not self.selected_column_name in self.data.domain:
            self.warning(f'Previously selected column "{self.selected_column_name}" does not exist in your data.')
            return

        if not isinstance(self.data.domain[self.selected_column_name], StringVariable):
            self.error('You must select a text variable.')
            return

        # Start progress bar
        self.progressBarInit()

        # Connect and start thread : main function, progress, result and finish
        # --> progress is used in the main function to track progress (with a callback)
        # --> result is used to collect the result from main function
        # --> finish is just an empty signal to indicate that the thread is finished

        # NOTE: La fonction audio.transcription prend 7 arguments (en plus des 2 arguments par défaut à la fin)
        self.thread = thread_management.Thread(
            audio.transcription,
            self.data,
            self.model,
            self.embedding_model,
            self.audio_helper,
            self.ffmpeg_path,
            self.selected_column_name
        )
        self.thread.progress.connect(self.handle_progress)
        self.thread.result.connect(self.handle_result)
        self.thread.finish.connect(self.handle_finish)
        self.thread.start()

    def handle_progress(self, value: float) -> None:
        self.progressBarSet(value)

    def handle_result(self, result):
        try:
            self.result = result
            self.Outputs.data.send(result)
        except Exception as e:
            print("An error occurred when sending out_data:", e)
            self.Outputs.data.send(None)
            return

    def handle_finish(self):
        self.progressBarFinished()

    def post_initialized(self):
        pass


if __name__ == "__main__":
    app = QApplication(sys.argv)
    my_widget = OWSpeechToText()
    my_widget.show()
    if hasattr(app, "exec"):
        app.exec()
    else:
        app.exec_()