from pathlib import Path
from collections import OrderedDict

from qgis.PyQt import QtWidgets, QtCore
from qgis.gui import QgsCollapsibleGroupBox
from qgis.core import QgsApplication

from . import tuflow_binaries, AddBinaryForm
from ..compatibility_routines import (QT_ABSTRACT_ITEM_VIEW_NO_EDIT_TRIGGERS, QT_ABSTRACT_ITEM_VIEW_SINGLE_SELECTION,
                                      QT_ABSTRACT_ITEM_VIEW_SELECT_ROWS, QT_DIALOG_ACCEPTED)


class BinaryLocationsMixin:

    folders_changed = QtCore.pyqtSignal()
    bins_changed = QtCore.pyqtSignal()

    def _init_binary_locations(self, layout: QtWidgets.QBoxLayout) -> QtWidgets.QWidget:
        self.binary_locations_widget = QtWidgets.QWidget()
        self.binary_locations_layout = QtWidgets.QVBoxLayout()
        self.binary_locations_widget.setLayout(self.binary_locations_layout)
        layout.addWidget(self.binary_locations_widget)

        # installed locations
        self.group_box_installed_locations = QgsCollapsibleGroupBox()
        self.group_box_installed_locations.setTitle('Installed TUFLOW binary locations')
        self.group_box_installed_locations.setToolTip(
            'This is a read-only list of TUFLOW binary locations that have been added via an installer'
        )
        self.install_locations_layout = QtWidgets.QVBoxLayout()
        self.group_box_installed_locations.setLayout(self.install_locations_layout)
        self.installed_locations = QtWidgets.QListWidget()
        self.installed_locations.setEditTriggers(QT_ABSTRACT_ITEM_VIEW_NO_EDIT_TRIGGERS)
        self.install_locations_layout.addWidget(self.installed_locations)
        self.binary_locations_layout.addWidget(self.group_box_installed_locations)

        self.refresh_install_locations()

        # binary folder locations
        self.group_box_bin_folders = QgsCollapsibleGroupBox()
        self.group_box_bin_folders.setTitle('User added TUFLOW release directories')
        self.group_box_bin_folders.setToolTip(
            'This is a list of TUFLOW release directories that have been added by the user. The added directory can '
            'point to a directory that contains a subdirectory of TUFLOW releases, or it can be a directory that contains '
            'the TUFLOW.exe binary directly.'
        )
        self.bin_folders_layout = QtWidgets.QVBoxLayout()
        self.group_box_bin_folders.setLayout(self.bin_folders_layout)
        self.add_folder_btn = QtWidgets.QToolButton()
        self.add_folder_btn.clicked.connect(self.add_folder_btn_triggered)
        self.add_folder_btn.setToolTip('Add folder')
        self.add_folder_btn.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg'))
        self.rem_folder_btn = QtWidgets.QToolButton()
        self.rem_folder_btn.clicked.connect(self.rem_folder_btn_triggered)
        self.rem_folder_btn.setToolTip('Remove selected folder')
        self.rem_folder_btn.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg'))
        self.folder_btn_layout = QtWidgets.QHBoxLayout()
        self.folder_btn_layout.addWidget(self.add_folder_btn)
        self.folder_btn_layout.addWidget(self.rem_folder_btn)
        self.folder_btn_layout.addStretch()
        self.bin_folders_layout.addLayout(self.folder_btn_layout)
        self.bin_folder_locations = QtWidgets.QListWidget()
        self.bin_folder_locations.setEditTriggers(QT_ABSTRACT_ITEM_VIEW_NO_EDIT_TRIGGERS)
        self.bin_folder_locations.setSelectionMode(QT_ABSTRACT_ITEM_VIEW_SINGLE_SELECTION)
        self.bin_folder_locations.setSelectionBehavior(QT_ABSTRACT_ITEM_VIEW_SELECT_ROWS)
        self.bin_folders_layout.addWidget(self.bin_folder_locations)
        self.binary_locations_layout.addWidget(self.group_box_bin_folders)

        self.refresh_binary_folder_locations()

        # binary locations
        self.group_box_bin_locations = QgsCollapsibleGroupBox()
        self.group_box_bin_locations.setTitle('User added TUFLOW binary locations')
        self.group_box_bin_locations.setToolTip(
            'This is a list of TUFLOW binary locations that have been added by the user. The added location should '
            'point to the TUFLOW.exe binary directly.'
        )
        self.bin_locations_layout = QtWidgets.QVBoxLayout()
        self.group_box_bin_locations.setLayout(self.bin_locations_layout)
        self.add_bin_btn = QtWidgets.QToolButton()
        self.add_bin_btn.clicked.connect(self.add_bin_btn_triggered)
        self.add_bin_btn.setToolTip('Add binary')
        self.add_bin_btn.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg'))
        self.rem_bin_btn = QtWidgets.QToolButton()
        self.rem_bin_btn.clicked.connect(self.rem_bin_btn_triggered)
        self.rem_bin_btn.setToolTip('Remove selected binary')
        self.rem_bin_btn.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg'))
        self.edit_bin_btn = QtWidgets.QToolButton()
        self.edit_bin_btn.clicked.connect(self.edit_bin_btn_triggered)
        self.edit_bin_btn.setToolTip('Edit selected binary')
        self.edit_bin_btn.setIcon(QgsApplication.getThemeIcon('/mActionToggleEditing.svg'))
        self.bin_btn_layout = QtWidgets.QHBoxLayout()
        self.bin_btn_layout.addWidget(self.add_bin_btn)
        self.bin_btn_layout.addWidget(self.rem_bin_btn)
        self.bin_btn_layout.addWidget(self.edit_bin_btn)
        self.bin_btn_layout.addStretch()
        self.bin_locations_layout.addLayout(self.bin_btn_layout)
        self.bin_locations_individual = QtWidgets.QTableWidget()
        self.bin_locations_individual.setColumnCount(2)
        self.bin_locations_individual.horizontalHeader().setStretchLastSection(True)
        self.bin_locations_individual.setEditTriggers(QT_ABSTRACT_ITEM_VIEW_NO_EDIT_TRIGGERS)
        self.bin_locations_individual.setSelectionMode(QT_ABSTRACT_ITEM_VIEW_SINGLE_SELECTION)
        self.bin_locations_individual.setSelectionBehavior(QT_ABSTRACT_ITEM_VIEW_SELECT_ROWS)
        self.bin_locations_layout.addWidget(self.bin_locations_individual)
        self.binary_locations_layout.addWidget(self.group_box_bin_locations)

        self.refresh_binary_locations()

        self.binary_locations_widget.hide()
        return self.binary_locations_widget

    def refresh_install_locations(self):
        self.installed_locations.clear()
        items = tuflow_binaries.load_installed_tuflow_versions()
        for loc in items.values():
            item = QtWidgets.QListWidgetItem(loc)
            item.setToolTip(loc)
            self.installed_locations.addItem(item)

    def refresh_binary_folder_locations(self):
        self.bin_folder_locations.clear()
        for folder in tuflow_binaries.user_folders:
            self.bin_folder_locations.addItem(str(folder))

    def refresh_binary_locations(self):
        self.bin_locations_individual.clear()
        self.bin_locations_individual.setHorizontalHeaderLabels(['Version', 'Path'])
        count = len(tuflow_binaries.user_bin_locations)
        self.bin_locations_individual.setRowCount(count)
        for i, (name, location) in enumerate(tuflow_binaries.user_bin_locations.items()):
            name_item = QtWidgets.QTableWidgetItem(name)
            name_item.setToolTip(name)
            location_item = QtWidgets.QTableWidgetItem(location)
            location_item.setToolTip(location)
            self.bin_locations_individual.setItem(i, 0, name_item)
            self.bin_locations_individual.setItem(i, 1, location_item)

    def add_folder_btn_triggered(self):
        folder = QtWidgets.QFileDialog.getExistingDirectory(self, 'Select TUFLOW release directory')
        if folder:
            folder = Path(folder)
            folders = [Path(x) for x in tuflow_binaries.user_folders]
            if folder not in folders:
                tuflow_binaries.user_folders.append(str(folder))
                tuflow_binaries.save_tuflow_settings_cache()
                self.refresh_binary_folder_locations()
                self.folders_changed.emit()

    def rem_folder_btn_triggered(self):
        item = self.bin_folder_locations.currentItem()
        if item:
            folder = Path(item.text())
            folders = [Path(x) for x in tuflow_binaries.user_folders]
            if folder in folders:
                i = folders.index(folder)
                tuflow_binaries.user_folders.pop(i)
                tuflow_binaries.save_tuflow_settings_cache()
                self.refresh_binary_folder_locations()
                self.folders_changed.emit()

    def add_bin_btn_triggered(self):
        dlg = AddBinaryForm(self)
        if dlg.exec() == QT_DIALOG_ACCEPTED:
            # assume the version name is unique and checked by the dialog class
            tuflow_binaries.user_bin_locations[dlg.version_name] = str(Path(dlg.bin_location))
            tuflow_binaries.save_tuflow_settings_cache()
            self.refresh_binary_locations()
            self.bins_changed.emit()

    def edit_bin_btn_triggered(self):
        item = self.bin_locations_individual.currentItem()
        if item:
            row = item.row()
            version_item = self.bin_locations_individual.item(row, 0)
            location_item = self.bin_locations_individual.item(row, 1)
            if version_item and location_item:
                version = version_item.text()
                location = location_item.text()
                dlg = AddBinaryForm(self, key=version, value=location)
                if dlg.exec() == QT_DIALOG_ACCEPTED:
                    # assume the version name is unique and checked by the dialog class
                    # remove old entry if version name has changed
                    idx = [x for x in tuflow_binaries.user_bin_locations.keys()].index(version)
                    d = OrderedDict()
                    for i, (k, v) in enumerate(tuflow_binaries.user_bin_locations.items()):
                        if i == idx:
                            d[dlg.version_name] = str(Path(dlg.bin_location))
                        elif k != version:
                            d[k] = v
                    tuflow_binaries.user_bin_locations = d
                    tuflow_binaries.save_tuflow_settings_cache()
                    self.refresh_binary_locations()
                    self.bins_changed.emit()

    def rem_bin_btn_triggered(self):
        item = self.bin_locations_individual.currentItem()
        if item:
            row = item.row()
            version_item = self.bin_locations_individual.item(row, 0)
            if version_item:
                version = version_item.text()
                if version in tuflow_binaries.user_bin_locations:
                    del tuflow_binaries.user_bin_locations[version]
                    tuflow_binaries.save_tuflow_settings_cache()
                    self.refresh_binary_locations()
                    self.bins_changed.emit()
