import sys
from os.path import basename, join, dirname

from enmapbox.gui.enmapboxgui import EnMAPBox
from enmapbox.qgispluginsupport.qps.processing.algorithmdialog import AlgorithmDialog
from enmapboxprocessing.algorithm.prepareregressiondatasetfromcodealgorithm import \
    PrepareRegressionDatasetFromCodeAlgorithm
from enmapboxprocessing.algorithm.prepareregressiondatasetfromcontinuouslibraryalgorithm import \
    PrepareRegressionDatasetFromContinuousLibraryAlgorithm
from enmapboxprocessing.algorithm.prepareregressiondatasetfromcontinuousrasteralgorithm import \
    PrepareRegressionDatasetFromContinuousRasterAlgorithm
from enmapboxprocessing.algorithm.prepareregressiondatasetfromcontinuousvectoralgorithm import \
    PrepareRegressionDatasetFromContinuousVectorAlgorithm
from enmapboxprocessing.algorithm.prepareregressiondatasetfromcontinuousvectorandfieldsalgorithm import \
    PrepareRegressionDatasetFromContinuousVectorAndFieldsAlgorithm
from enmapboxprocessing.algorithm.prepareregressiondatasetfromfilesalgorithm import \
    PrepareRegressionDatasetFromFilesAlgorithm
from enmapboxprocessing.algorithm.prepareregressiondatasetfromjsonalgorithm import \
    PrepareRegressionDatasetFromJsonAlgorithm
from enmapboxprocessing.algorithm.prepareregressiondatasetfromtablealgorithm import \
    PrepareRegressionDatasetFromTableAlgorithm
from enmapboxprocessing.typing import RegressorDump
from enmapboxprocessing.utils import Utils
from processing.gui.wrappers import WidgetWrapper
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QWidget, QToolButton, QMenu, QMessageBox
from qgis.PyQt.uic import loadUi
from qgis.gui import QgsFileWidget


class ProcessingParameterSkopsFileRegressionDatasetWidget(QWidget):
    mFile: QgsFileWidget
    mCreate: QToolButton
    mEdit: QToolButton

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        loadUi(join(dirname(__file__), 'processingparameterskopsfilewidget.ui'), self)

        self.menu = QMenu()
        self.menu.setToolTipsVisible(True)

        for alg, icon in [
            (PrepareRegressionDatasetFromContinuousVectorAlgorithm(),
             QIcon(':/images/themes/default/mIconVector.svg')),

            (PrepareRegressionDatasetFromContinuousRasterAlgorithm(),
             QIcon(':/images/themes/default/algorithms/mAlgorithmRandomRaster.svg')),

            (PrepareRegressionDatasetFromContinuousLibraryAlgorithm(),
             QIcon(':/qps/ui/icons/speclib.svg')),

            (PrepareRegressionDatasetFromContinuousVectorAndFieldsAlgorithm(),
             QIcon(':/images/themes/default/mActionOpenTable.svg')),

            (PrepareRegressionDatasetFromTableAlgorithm(),
             QIcon(':/images/themes/default/mActionOpenTable.svg')),

            (PrepareRegressionDatasetFromCodeAlgorithm(),
             QIcon(':/images/themes/default/mIconPythonFile.svg')),

            (PrepareRegressionDatasetFromFilesAlgorithm(),
             QIcon(':/images/themes/default/mIconFile.svg')),

            (PrepareRegressionDatasetFromJsonAlgorithm(),
             QIcon(':/images/themes/default/mIconFieldJson.svg'))
        ]:
            action = self.menu.addAction(alg.displayName())
            action.setIcon(icon)
            action.setText(alg.displayName())
            action.triggered.connect(self.onCreateClicked)
            action.alg = alg

        if EnMAPBox.instance() is not None:
            self.menu.addSeparator()
            for filename in EnMAPBox.instance().dataSources('MODEL', True):
                if not filename.endswith('.skops'):
                    continue
                try:
                    dump = RegressorDump.fromDict(Utils.modelLoad(filename))
                    samples, features = dump.X.shape
                    targets = len(dump.targets)
                except Exception as ex:
                    print(f'Unable to open .skops file: {ex}', file=sys.stderr)
                    continue

                action = self.menu.addAction('')
                action.setIcon(QIcon(':/images/themes/default/mIconFile.svg'))
                action.setText(basename(filename) + f' ({samples} samples, {features} features, {targets} targets)')
                action.setToolTip(rf'<html><head/><body><p>{filename}</p></body></html>')
                action.triggered.connect(self.onFilenameClicked)
                action.filename = filename

        self.mCreate.setMenu(self.menu)
        self.mEdit.clicked.connect(self.onEditClicked)

    def value(self) -> str:
        return self.mFile.filePath()

    def setValue(self, value):
        self.mFile.setFilePath(value)

    filePath = value
    setFilePath = setValue

    def onCreateClicked(self):
        from enmapbox.gui.enmapboxgui import EnMAPBox
        enmapBox = EnMAPBox.instance()

        class AlgorithmDialogWrapper(AlgorithmDialog):
            def finish(self_, successful, result, context, feedback, in_place=False):
                super().finish(successful, result, context, feedback, in_place)
                if successful:
                    filename = result['outputRegressionDataset']
                    self.mFile.setFilePath(filename)

                    dump = RegressorDump.fromDict(Utils.modelLoad(filename))
                    samples, features = dump.X.shape
                    targets = len(dump.targets)

                    # add to the list!
                    action = self.menu.addAction(alg.displayName())
                    action.setIcon(QIcon(':/images/themes/default/mIconFile.svg'))
                    action.setText(basename(filename) + f' ({samples} samples, {features} features, {targets} targets)')
                    action.setToolTip(rf'<html><head/><body><p>{filename}</p></body></html>')
                    action.triggered.connect(self.onFilenameClicked)
                    action.filename = filename

                    self_.close()

        alg = self.sender().alg

        if enmapBox is None:
            QMessageBox.information(self, 'Information', 'EnMAP-Box not running.')
            return

        enmapBox.showProcessingAlgorithmDialog(alg, modal=True, wrapper=AlgorithmDialogWrapper, parent=self)

    def onFilenameClicked(self):
        filename = self.sender().filename
        self.mFile.setFilePath(filename)

    def onEditClicked(self):
        filename = self.mFile.filePath()
        from regressiondatasetmanagerapp import RegressionDatasetManagerGui
        self.dialog = RegressionDatasetManagerGui(self)
        self.dialog.mDataset.mFile.setFilePath(filename)
        self.dialog.exec()
        filename = self.dialog.mDataset.mFile.filePath()

        QMessageBox.information(self, 'Regression Dataset Manager', f'New dataset file {basename(filename)}.')
        self.mFile.setFilePath(filename)


class ProcessingParameterSkopsFileRegressionDatasetWidgetWrapper(WidgetWrapper):
    widget: ProcessingParameterSkopsFileRegressionDatasetWidget

    def createWidget(self):
        return ProcessingParameterSkopsFileRegressionDatasetWidget()

    def setValue(self, value):
        self.widget.setValue(value)

    def value(self):
        return self.widget.value()
