from PySide6.QtWidgets import (
    QMainWindow,
    QMessageBox,
    QFileDialog,
    QInputDialog,
    QStyle,
    QLineEdit,
    QTabWidget,
    QGridLayout,
    QLabel,
    QSizePolicy,
    QSpacerItem,
    QWidget,
    QTabBar,
    QDialog,
    QPushButton,
    QStyleOptionButton,
)
from PySide6.QtGui import QAction, QIcon, QPixmap, QFont, QCloseEvent
from PySide6.QtCore import QCoreApplication, Qt, QThreadPool
from PySide6.QtSvgWidgets import QSvgWidget
import os
from swane.utils.DependencyManager import (
    DependencyManager,
    Dependence,
    DependenceStatus,
)
from swane.ui.SubjectTab import SubjectTab
from swane.ui.PreferencesWindow import PreferencesWindow
import swane_supplement
from swane import __version__, EXIT_CODE_REBOOT, strings
from swane.workers.UpdateCheckWorker import UpdateCheckWorker
from swane.utils.Subject import Subject, SubjectRet
from swane.config.ConfigManager import ConfigManager
from swane.config.config_enums import GlobalPrefCategoryList


class MainWindow(QMainWindow):
    """
    Custom implementation of PySide QMainWindow to define SWANe GUI.

    """

    def __init__(self, global_config: ConfigManager):

        super(MainWindow, self).__init__()

        # GUI configuration setting
        self.global_config: ConfigManager = global_config
        self.dependency_manager: DependencyManager = DependencyManager()
        self.global_config.check_dependencies(self.dependency_manager)

        # GUI Icons setting
        self.setWindowIcon(QIcon(QPixmap(swane_supplement.appIcon_file)))
        self.OK_ICON_FILE = swane_supplement.okIcon_file
        self.ERROR_ICON_FILE = swane_supplement.errorIcon_file
        self.WARNING_ICON_FILE = swane_supplement.warnIcon_file
        self.LOADING_MOVIE_FILE = swane_supplement.loadingMovie_file
        self.VOID_SVG_FILE = swane_supplement.voidsvg_file
        self.OK_ICON = QPixmap(self.OK_ICON_FILE)
        self.ERROR_ICON = QPixmap(self.ERROR_ICON_FILE)
        self.WARNING_ICON = QPixmap(self.WARNING_ICON_FILE)
        self.NON_UNICODE_BUTTON_HEIGHT = MainWindow.get_non_unicode_height()

        # subject folder configuration checking
        while self.global_config.get_main_working_directory() == "":
            msg_box = QMessageBox()
            msg_box.setText(strings.mainwindow_choose_working_dir)
            msg_box.exec()
            self.set_main_working_directory()

        # subject folder configuration setting
        os.chdir(self.global_config.get_main_working_directory())

        self.initialize_ui()

        # Check for update
        update_thread = UpdateCheckWorker()
        update_thread.signal.last_available.connect(
            lambda pip_version: self.update_available(pip_version)
        )
        QThreadPool.globalInstance().start(update_thread)

    def update_available(self, pip_version: str):
        """
        Called if UpdateCheckWorker detect a newer version on pip
        Parameters
        ----------
        pip_version: str
            The version of the update available on pip
        """
        msg_box = QMessageBox(parent=self)
        msg_box.setIcon(QMessageBox.Icon.Information)
        msg_box.setText(strings.mainwindow_update_available % pip_version)
        msg_box.exec()

    @staticmethod
    def get_non_unicode_height() -> int:
        """
        Returns
        -------
        The pixel height of a generic label WITHOUT unicode character
        """
        button = QPushButton()
        opt = QStyleOptionButton()
        opt.initFrom(button)
        text_size = button.fontMetrics().size(Qt.TextShowMnemonic, button.text())
        return (
            button.style()
            .sizeFromContents(QStyle.CT_PushButton, opt, text_size, button)
            .height()
        )

    def open_subject_tab(self, subject: Subject, check_dicom_folders: bool = True):
        """
        Load a checked and valid subject folder.

        Parameters
        ----------
        subject : str
            The subject to load in the tab.

        check_dicom_folders : bool
            If True, check for dicom files in the fubject folders. Default is True.

        Returns
        -------
        None.

        """

        this_tab = SubjectTab(
            self.global_config, subject, main_window=self, parent=self.main_tab
        )
        self.subject_tab_array.append(this_tab)

        self.main_tab.addTab(this_tab, os.path.basename(subject.name))
        self.main_tab.setCurrentWidget(this_tab)

        this_tab.load_subject(check_dicom_folders)

    def check_subject_limit(self) -> bool:
        """
        Check if SWANe can open another subject tab without overcome the limit set by configuration.

        Returns
        -------
        bool
            True if SWANe can load another tab, otherwise False.

        """

        max_subjects = self.global_config.get_max_subject_tabs()
        if max_subjects <= 0:
            return True
        if len(self.subject_tab_array) >= max_subjects:
            msg_box = QMessageBox()
            msg_box.setIcon(QMessageBox.Icon.Warning)
            msg_box.setText(strings.mainwindow_max_subj_error)
            msg_box.exec()
            return False
        return True

    def search_subject_dir(self, button_state: bool = False, folder_path: str = None):
        """
        Try to open a subject directory

        Parameters
        ----------
        button_state: bool
            Not used, passed by QPushButton. Default is False
        folder_path: str
            The folder to load. Default is None

        Returns
        -------
        None.

        """

        # Guard to avoid the opening of subject tabs greater than the maximum allowed
        if not self.check_subject_limit():
            return

        if folder_path is None:
            # Open the directory selection dialog if a path is not provided
            file_dialog = QFileDialog()
            file_dialog.setDirectory(self.global_config.get_main_working_directory())
            folder_path = file_dialog.getExistingDirectory(
                self, strings.mainwindow_select_subj_folder
            )

        subject = Subject(
            self.global_config, dependency_manager=self.dependency_manager
        )

        # Guard to avoid an already loaded subject directory
        for tab in self.subject_tab_array:
            if tab.subject.folder == folder_path:
                msg_box = QMessageBox()
                msg_box.setIcon(QMessageBox.Icon.Warning)
                msg_box.setText(strings.mainwindow_subj_already_loaded_error)
                msg_box.exec()
                return

        subject_load_ret = subject.load(folder_path)

        if subject_load_ret == SubjectRet.ValidFolder:
            self.open_subject_tab(subject)
        elif subject_load_ret == SubjectRet.FolderNotFound:
            # User canceled subject load
            return
        elif subject_load_ret == SubjectRet.PathBlankSpaces:
            # Guard to avoid the opening a directory containing blank spaces
            msg_box = QMessageBox()
            msg_box.setIcon(QMessageBox.Icon.Critical)
            msg_box.setText(strings.mainwindow_subj_folder_with_blank_spaces_error)
            msg_box.exec()
            return
        elif subject_load_ret == SubjectRet.FolderOutsideMain:
            # Guard to avoid the opening of a directory outside the main subject folder
            msg_box = QMessageBox()
            msg_box.setIcon(QMessageBox.Icon.Critical)
            msg_box.setText(strings.mainwindow_subj_folder_outside_workingdir_error)
            msg_box.exec()
            return
        elif subject_load_ret == SubjectRet.InvalidFolderTree:
            # Check if selected folder is a valid subject folder
            msg_box = QMessageBox()
            msg_box.setIcon(QMessageBox.Icon.Warning)
            msg_box.setText(strings.mainwindow_invalid_folder_error)
            msg_box.exec()

            msg_box2 = QMessageBox()
            msg_box2.setText(strings.mainwindow_force_dir_update)
            msg_box2.setIcon(QMessageBox.Icon.Question)
            msg_box2.setStandardButtons(
                QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
            )
            msg_box2.button(QMessageBox.StandardButton.Yes).setText("Yes")
            msg_box2.button(QMessageBox.StandardButton.No).setText("No")
            msg_box2.setDefaultButton(QMessageBox.StandardButton.No)
            ret = msg_box2.exec()

            # A subject folder has a predefined folder tree.
            # SWANe recognizes a subject folder checking its subfolders.
            # If a selected folder is not valid, the user may force its conversion into a subject folder.
            if ret == QMessageBox.StandardButton.Yes:
                subject.fix_subject_folder_subtree(folder_path)
                self.search_subject_dir(folder_path=folder_path)
            return

        return

    def get_suggested_subject_name(self) -> str:
        """
        Get a default name for the subject folder based the existing subject folders into the main subject directory.

        Returns
        -------
        str
            The suggested subject folder name.

        """

        import re

        regex = re.compile("^" + self.global_config.get_subjects_prefix() + r"\d+$")
        file_list = []

        for this_dir in os.listdir(self.global_config.get_main_working_directory()):
            if regex.match(this_dir):
                file_list.append(
                    int(this_dir.replace(self.global_config.get_subjects_prefix(), ""))
                )

        if len(file_list) == 0:
            return self.global_config.get_subjects_prefix() + "1"

        return self.global_config.get_subjects_prefix() + str(max(file_list) + 1)

    def choose_new_subject_dir(self):
        """
        Create a new subject folder. The user must specify its name.

        Returns
        -------
        None.

        """

        if not self.check_subject_limit():
            return

        text, ok = QInputDialog.getText(
            self,
            strings.mainwindow_new_subj_title,
            strings.mainwindow_new_subj_name,
            QLineEdit.EchoMode.Normal,
            self.get_suggested_subject_name(),
        )

        if not ok:
            return

        subject_name = str(text).replace(" ", "_")
        subject = Subject(
            self.global_config, dependency_manager=self.dependency_manager
        )
        create_subject_ret = subject.create_new_subject_dir(subject_name)

        if (
            create_subject_ret == SubjectRet.FolderNotFound
            or create_subject_ret == SubjectRet.PathBlankSpaces
        ):
            msg_box = QMessageBox()
            msg_box.setText(strings.mainwindow_new_subj_name_error + subject_name)
            msg_box.exec()
            return
        elif create_subject_ret == SubjectRet.FolderAlreadyExists:
            msg_box = QMessageBox()
            msg_box.setText(strings.mainwindow_subj_exists_error + subject_name)
            msg_box.exec()
            return
        elif create_subject_ret == SubjectRet.ValidFolder:
            msg_box = QMessageBox()
            msg_box.setText(strings.mainwindow_new_subj_created + subject_name)
            msg_box.exec()
            self.open_subject_tab(subject, check_dicom_folders=False)

    def set_main_working_directory(self):
        """
        Generates the OS directory selection dialog to set the default subject folder

        Returns
        -------
        None.

        """

        folder_path = QFileDialog.getExistingDirectory(
            self, strings.mainwindow_choose_working_dir_title
        )

        if not os.path.exists(folder_path):
            return

        if " " in folder_path:
            msg_box = QMessageBox()
            msg_box.setText(strings.mainwindow_working_dir_space_error)
            msg_box.exec()
            return

        self.global_config.set_main_working_directory(os.path.abspath(folder_path))

        os.chdir(folder_path)

    def edit_config(self):
        """
        Open the Global Preferences Window.

        Returns
        -------
        None.

        """

        if self.check_running_workflows():
            msg_box = QMessageBox()
            msg_box.setText(strings.mainwindow_pref_disabled_error)
            msg_box.exec()
            return

        preference_window = PreferencesWindow(
            self.global_config, self.dependency_manager, False
        )
        ret = preference_window.exec()

        if ret == EXIT_CODE_REBOOT:
            self.close()
            QCoreApplication.exit(EXIT_CODE_REBOOT)

        if ret != 0:
            self.reset_workflows()

    def edit_wf_config(self):
        """
        Open the Default Workflow Settings Window.

        Returns
        -------
        None.

        """

        if self.check_running_workflows():
            msg_box = QMessageBox()
            msg_box.setText(strings.mainwindow_pref_disabled_error)
            msg_box.exec()
            return

        wf_preference_window = PreferencesWindow(
            self.global_config, self.dependency_manager, True
        )
        ret = wf_preference_window.exec()

        if ret == -1:
            self.global_config.reset_to_defaults()
            self.edit_wf_config()

    def toggle_shutdown_after_workflow(self):
        """
        Toggle shutdown after woprkflow preference

        Returns
        -------
        None.

        """
        shutdown = self.global_config.getboolean_safe(
            GlobalPrefCategoryList.MAIN, "shutdown"
        )
        self.global_config[GlobalPrefCategoryList.MAIN]["shutdown"] = str(not shutdown)

    def check_running_workflows(self, ignore_subj: Subject = None) -> bool:
        """
        Check if SWANe is executing a workflow in any open subject tab.

        Parameters
        ----------
        ignore_subj : Subject
            The subject tab to be ignored. Default is None

        Returns
        -------
        bool
            True if SWANe is executing a workflow, otherwise False.

        """

        for subj in self.subject_tab_array:
            if subj.subject != ignore_subj and subj.subject.is_workflow_process_alive():
                return True

        return False

    def check_workflow_error(self) -> bool:
        """
        Check if there was a node error in any open subject tab.

        Returns
        -------
        bool
            True if there was any error, otherwise False.

        """

        for subj in self.subject_tab_array:
            if subj.workflow_had_error:
                return True
        return False

    def reset_workflows(self):
        """
        Reset all the generated workflows that are not already running.

        Returns
        -------
        None.

        """

        for subj in self.subject_tab_array:
            subj.reset_workflow()

    def about(self):
        """
        Open the About Window.

        Returns
        -------
        None.

        """

        about_dialog = QDialog(parent=self)
        layout = QGridLayout()

        bold_font = QFont()
        bold_font.setBold(True)
        title_font = QFont()
        title_font.setBold(True)
        title_font.setPointSize(title_font.pointSize() * 1.5)

        label_about1 = QLabel(strings.APPNAME)
        label_about1.setFont(title_font)
        label_about2 = QLabel(strings.app_acronym)
        label_about3 = QLabel("Version: " + __version__)

        label_about4 = QLabel(strings.aboutwindow_wiki_changelog)
        label_about5 = QLabel(strings.aboutwindow_wiki_dependencylist)

        label_about_icon = QLabel()
        icon = QPixmap(swane_supplement.appIcon_file)

        label_about_icon.setPixmap(icon.scaled(60, 60))

        layout.addWidget(label_about1, 0, 1)
        layout.addWidget(label_about2, 1, 1)
        layout.addWidget(label_about3, 2, 1)
        layout.addWidget(label_about4, 3, 1)
        layout.addWidget(label_about5, 4, 1)

        layout.addWidget(label_about_icon, 0, 0, 3, 1)

        about_dialog.setLayout(layout)
        about_dialog.exec()

    def initialize_ui(self):
        """
        Generates the SWANE GUI

        Returns
        -------
        None.

        """

        self.resize(800, 600)
        self.setWindowTitle(strings.APPNAME + " - " + strings.app_acronym)

        self.statusBar().showMessage("")

        # Buttons definition
        button_action = QAction(
            QIcon.fromTheme("document-open"), strings.menu_load_subj, self
        )
        button_action.setStatusTip(strings.menu_load_subj_tip)
        button_action.triggered.connect(self.search_subject_dir)

        button_action2 = QAction(
            QIcon.fromTheme("document-new"), strings.menu_new_subj, self
        )
        button_action2.setStatusTip(strings.menu_new_subj_tip)
        button_action2.triggered.connect(self.choose_new_subject_dir)

        button_action3 = QAction(
            QIcon.fromTheme("application-exit"), strings.menu_exit, self
        )
        button_action3.triggered.connect(self.close)

        button_action4 = QAction(
            QIcon.fromTheme("preferences-other"), strings.menu_pref, self
        )
        button_action4.setStatusTip(strings.menu_pref_tip)
        button_action4.triggered.connect(self.edit_config)

        button_action5 = QAction(
            QIcon.fromTheme("preferences-other"), strings.menu_wf_pref, self
        )
        button_action5.triggered.connect(self.edit_wf_config)

        button_action6 = QAction(strings.menu_shutdown_pref, self)
        button_action6.setCheckable(True)
        button_action6.triggered.connect(self.toggle_shutdown_after_workflow)

        button_action7 = QAction(strings.menu_about, self)
        button_action7.triggered.connect(self.about)

        # Menu definition and population
        menu = self.menuBar()
        menu.setNativeMenuBar(False)
        file_menu = menu.addMenu(strings.menu_file_name)
        file_menu.addAction(button_action)
        file_menu.addAction(button_action2)
        file_menu.addAction(button_action3)
        tool_menu = menu.addMenu(strings.menu_tools_name)
        tool_menu.addAction(button_action4)
        tool_menu.addAction(button_action5)
        tool_menu.addAction(button_action6)
        help_menu = menu.addMenu(strings.menu_help_name)
        help_menu.addAction(button_action7)

        # Tab definition
        self.main_tab = QTabWidget(parent=self)
        self.main_tab.setTabsClosable(True)
        self.main_tab.tabCloseRequested.connect(self.close_subject_tab)
        self.setCentralWidget(self.main_tab)
        self.homeTab = QWidget()
        self.main_tab.addTab(self.homeTab, strings.mainwindow_home_tab_name)

        # Tab closing option disabled
        self.main_tab.tabBar().setTabButton(0, QTabBar.ButtonPosition.LeftSide, None)
        self.main_tab.tabBar().setTabButton(0, QTabBar.ButtonPosition.RightSide, None)

        # Home Tab definition
        self.home_tab_ui()

        self.subject_tab_array = []

        # Link to ChatGPT SWANe Assistant - as a clear clickable QPushButton
        chatgpt_url = (
            "https://chatgpt.com/g/g-68e14421a54c8191a2110a831824f1e9-swaneassistant/"
        )
        chatgpt_text = f"🤖 {strings.mainwindow_chatgpt_title}"

        self.chatgpt_button = QPushButton(chatgpt_text, parent=self)
        self.chatgpt_button.setCursor(Qt.PointingHandCursor)
        self.chatgpt_button.setToolTip(strings.mainwindow_chatgpt_tooltip)
        self.chatgpt_button.setMinimumHeight(28)
        self.chatgpt_button.setContentsMargins(4, 0, 4, 0)
        self.chatgpt_button.setStyleSheet(
            """
            QPushButton {
                color: #ffffff;
                background-color: rgba(0, 102, 204, 0.12);
                padding: 6px 12px;
                border: 1px solid rgba(0, 102, 204, 0.20);
                border-radius: 8px;
                font-weight: 600;
                font-size: 13px;
            }
            QPushButton:hover {
                background-color: rgba(0, 102, 204, 0.18);
            }
            QPushButton:pressed {
                background-color: rgba(0, 102, 204, 0.24);
            }
        """
        )

        def _open_chatgpt():
            import webbrowser

            webbrowser.open(chatgpt_url)

        self.chatgpt_button.clicked.connect(_open_chatgpt)

        # Add to status bar (use addPermanentWidget per preferenza)
        self.statusBar().addPermanentWidget(self.chatgpt_button)

        self.show()

    def close_subject_tab(self, index: int):
        """
        Handle the PySide tab closing event for the subject tab.

        Parameters
        ----------
        index : int
            The subject tab index into the GUI.

        Returns
        -------
        None.

        """

        # Guard to prevent the Home Tab closing
        if index <= 0:
            return

        tab_item = self.main_tab.widget(index)
        if tab_item.subject.is_workflow_process_alive():
            msg_box = QMessageBox()
            msg_box.setText(strings.mainwindow_wf_executing_error_1)
            msg_box.exec()
            return

        tab_item.subject.config.save()

        self.subject_tab_array.remove(tab_item)
        self.main_tab.removeTab(index)

    def closeEvent(self, event: QCloseEvent):
        """
        Prevent the closing of a running workflow tab

        Parameters
        ----------
        event : QCloseEvent
            PySide QCloseEvent.

        Returns
        -------
        None.

        """

        if not self.check_running_workflows():
            event.accept()
        else:
            msg_box = QMessageBox()
            msg_box.setText(strings.mainwindow_wf_executing_error_2)
            msg_box.exec()
            event.ignore()

    def safe_shutdown_after_workflow(self, subject: Subject):
        """
        Shutdown pc if all workflows are completed

        Parameters
        ----------
        subject: Subject
            The subject tab asking to shutdown

        Returns
        -------
        None.

        """

        if (
            not self.check_running_workflows(ignore_subj=subject)
            and not self.check_workflow_error()
        ):
            os.system("systemctl poweroff")
            os.system("osascript -e 'tell app \"System Events\" to shut down'")
            exit()
            pass

    def home_tab_ui(self):
        """
        Generates the Home Tab layout

        Returns
        -------
        None.

        """

        self.home_grid_layout = QGridLayout()

        bold_font = QFont()
        bold_font.setBold(True)
        title_font = QFont()
        title_font.setBold(True)
        title_font.setPointSize(title_font.pointSize() * 1.5)
        x = 0

        label_welcome1 = QLabel(strings.mainwindow_home_label1)
        label_welcome1.setFont(title_font)
        label_welcome2 = QLabel(strings.mainwindow_home_label2)
        label_welcome2.setWordWrap(True)
        label_welcome3 = QLabel(strings.mainwindow_home_label3)
        label_welcome3.setWordWrap(True)
        label_welcome4 = QLabel(strings.mainwindow_home_label4)
        label_welcome4.setFont(bold_font)

        self.home_grid_layout.addWidget(label_welcome1, x, 0, 1, 2)
        x += 1
        self.home_grid_layout.addWidget(label_welcome2, x, 0, 1, 2)
        x += 1
        self.home_grid_layout.addWidget(label_welcome3, x, 0, 1, 2)
        x += 1
        self.home_grid_layout.addWidget(label_welcome4, x, 0, 1, 2)
        x += 1

        # Main window dependency check
        label_main_dep = QLabel(strings.mainwindow_home_label5)
        label_main_dep.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        label_main_dep.setFont(bold_font)
        self.home_grid_layout.addWidget(label_main_dep, x, 0, 1, 2)
        x += 1

        x = self.add_home_entry(self.dependency_manager.dcm2niix, x)

        x = self.add_home_entry(self.dependency_manager.fsl, x)

        label_main_dep = QLabel(strings.mainwindow_home_label6)
        label_main_dep.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        label_main_dep.setFont(bold_font)
        self.home_grid_layout.addWidget(label_main_dep, x, 0, 1, 2)
        x += 1

        x = self.add_home_entry(self.dependency_manager.freesurfer, x)
        self.global_config.freesurfer = self.dependency_manager.is_freesurfer()

        if DependencyManager.need_slicer_check(self.global_config):
            self.slicer_x = x
            x = self.add_home_entry(
                Dependence(
                    DependenceStatus.CHECKING, strings.mainwindow_dep_slicer_src
                ),
                x,
            )
            DependencyManager.check_slicer(
                self.global_config.get_slicer_path(), self.slicer_row
            )
        else:
            label = (
                strings.check_dep_slicer_found % self.global_config.get_slicer_version()
            )
            x = self.add_home_entry(Dependence(DependenceStatus.DETECTED, label), x)

        label_main_dep = QLabel(strings.mainwindow_home_label7)
        label_main_dep.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        label_main_dep.setFont(bold_font)
        self.home_grid_layout.addWidget(label_main_dep, x, 0, 1, 2)
        x += 1

        x = self.add_home_entry(self.dependency_manager.graphviz, x)

        vertical_spacer = QSpacerItem(
            20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding
        )
        self.home_grid_layout.addItem(vertical_spacer, x, 0, 1, 2)

        self.homeTab.setLayout(self.home_grid_layout)

    def add_home_entry(self, dep: Dependence, x: int) -> int:
        """
        Generates a dependency check label, adding it to an existing layout

        Parameters
        ----------
        dep : Dependence
            A Dependence object to be parsed.
        x : int
            The starting grid layout row index.

        Returns
        -------
        int
            The next grid layout row index.

        """

        label_icon = QLabel()
        label_icon.setScaledContents(True)

        if dep.state == DependenceStatus.DETECTED:
            label_icon.setPixmap(self.OK_ICON)
        elif dep.state == DependenceStatus.WARNING:
            label_icon.setPixmap(self.WARNING_ICON)
        elif dep.state == DependenceStatus.CHECKING:
            label_icon = QSvgWidget()
            label_icon.load(self.LOADING_MOVIE_FILE)
        else:
            label_icon.setPixmap(self.ERROR_ICON)

        label_icon.setFixedSize(25, 25)

        old_icon_layout = self.home_grid_layout.itemAtPosition(x, 0)
        if old_icon_layout is not None:
            old_icon_layout.widget().deleteLater()
            self.home_grid_layout.removeItem(old_icon_layout)
        self.home_grid_layout.addWidget(label_icon, x, 0)

        label = QLabel(dep.label)
        label.setOpenExternalLinks(True)
        label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        old_label_layout = self.home_grid_layout.itemAtPosition(x, 1)
        if old_label_layout is not None:
            old_label_layout.widget().deleteLater()
            self.home_grid_layout.removeItem(old_label_layout)
        self.home_grid_layout.addWidget(label, x, 1)

        return x + 1

    def slicer_row(
        self, slicer_path: str, slicer_version: str, msg: str, state: DependenceStatus
    ):
        """
        Generates the Slicer dependency check label and path, if 3D Slicer is found.

        Parameters
        ----------
        slicer_path : str
            The local 3D Slicer path.
        slicer_version: str
            The Slicer version found
        msg : str
            The label message.
        state: DependenceStatus
            A state from DependenceStatus.

        Returns
        -------
        None.

        """

        self.add_home_entry(Dependence(state, msg), self.slicer_x)

        if state is DependenceStatus.DETECTED:
            self.global_config.set_slicer_path(slicer_path)
            self.global_config.set_slicer_version(slicer_version)
            self.global_config.save()

        for tab in self.subject_tab_array:
            tab.export_results_button_update_state()
            tab.load_scene_button_update_state()
