from enum import IntFlag

from qgis.PyQt.QtWidgets import (
    QGridLayout,
    QLabel,
    QMessageBox,
    QSizePolicy,
    QWidget,
    QWizard,
    QWizardPage,
)

from openlog.datamodel.connection.interfaces.write_interface import WriteInterface
from openlog.datamodel.connection.openlog_connection import OpenLogConnection
from openlog.datamodel.imports.import_classes import ImportType
from openlog.gui.import_data.wizard.collar import CollarsImportPageWizard
from openlog.gui.import_data.wizard.person_dataset import (
    PersonDatasetSelectionPageWizard,
)
from openlog.gui.import_data.wizard.survey import SurveysImportPageWizard
from openlog.plugins.manager import get_plugin_manager


class ConfirmationPageWizard(QWizardPage):
    def __init__(
        self,
        parent: QWidget,
        openlog_connection: OpenLogConnection,
        import_wizard_pages: [QWizardPage],
    ) -> None:
        """
        QWizardPage used to confirm data imports and commit database session

        Args:
            openlog_connection: OpenLogConnection used to import data
            import_wizard_pages: List of QWizardPage defining data to be imported
        """
        super().__init__(parent)
        self._openlog_connection = openlog_connection
        self._import_wizard_pages = import_wizard_pages
        self.skip_validation = False

        self.setTitle("Import summary")

        label = QLabel("Here are the data that will be imported in your connection.")
        label.setWordWrap(True)

        self.layout = QGridLayout()
        self.layout.addWidget(label, 0, 0, 1, 2)
        self.setLayout(self.layout)

    def initializePage(self) -> None:
        """
        Initialize page before show.

        Create a the list of imported data in the widget.

        """
        self._clean_layout()
        for import_wizard_page in self._import_wizard_pages:

            label = import_wizard_page.data_label()
            values = import_wizard_page.data_count()
            if not isinstance(label, tuple):
                label = [label]
                values = [values]

            for lab, val in zip(label, values):
                row = self.layout.rowCount()
                name_edit = QLabel(lab)
                name_edit.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
                self.layout.addWidget(name_edit, row + 1, 0)
                val_edit = QLabel(str(val))
                font = val_edit.font()
                font.setBold(True)
                val_edit.setFont(font)
                self.layout.addWidget(val_edit, row + 1, 1)

    def _clean_layout(self) -> None:
        while self.layout.count() > 1:
            layout_item = self.layout.takeAt(1)
            if layout_item.widget():
                layout_item.widget().deleteLater()

    def validatePage(self) -> bool:
        """
        Import data

        Returns: True if no import error occured, False otherwise

        """
        if self.skip_validation:
            return super().validatePage()
        valid = True
        try:
            for import_wizard_page in self._import_wizard_pages:
                import_wizard_page.import_data()
            self._openlog_connection.commit()
        except (
            OpenLogConnection.ImportException,
            WriteInterface.ImportException,
        ) as exc:
            valid = False
            QMessageBox.warning(self, "Import exception", str(exc))
            self._openlog_connection.rollback()
        return valid


class ImportPages(IntFlag):
    """
    Define flags for import pages
    For example ImportPages.COLLAR | ImportPages.SURVEY | ImportPages.LITH for Collar, Survey and Lithology import
    https://docs.python.org/fr/3/library/enum.html#intflag
    """

    COLLAR = 1
    SURVEY = 2


class DatabaseImportWizard(QWizard):
    def rejected(self) -> None:
        """
        Rollback openlog connection if data import is rejected

        """
        self.openlog_connection.rollback()
        super(DatabaseImportWizard).rejected()

    def __init__(
        self,
        openlog_connection: OpenLogConnection,
        parent: QWidget = None,
        import_pages=ImportPages.COLLAR | ImportPages.SURVEY,
    ) -> None:
        """
        QWizard to import data into xplordb database from .csv files.

        Args:
            openlog_connection: OpenLogConnection used to import data
            parent : QWidget parent
            import_pages: ImportPages flags to define which data can be imported for example ImportPages.COLLAR | ImportPages.SURVEY | ImportPages.LITH
        """
        super().__init__(parent)
        self.openlog_connection = openlog_connection
        self.wizard_type = (
            ImportType.COLLAR
            if import_pages == ImportPages.COLLAR
            else ImportType.SURVEY
        )

        # import profile actions
        self.profile_generator = (
            get_plugin_manager().get_advanced_imports_plugin().profile_generator(self)
        )
        self.profile_enabled = get_plugin_manager().get_advanced_imports_plugin().enable
        self.profile_btn = self.profile_generator.get_wizard_button()
        self.profile_btn.setEnabled(False)
        if not self.profile_enabled:
            self.profile_btn.setToolTip("Premium only")
        self.setWindowTitle("Data import")

        # List of wizard used to import data (data will be imported with list order)
        self.person_dataset_import_wizard = PersonDatasetSelectionPageWizard(
            self, self.openlog_connection
        )

        self.data_import_wizards = [self.person_dataset_import_wizard]

        self.import_wizard = None
        if ImportPages.COLLAR in import_pages:
            self.import_wizard = CollarsImportPageWizard(self, self.openlog_connection)

        if ImportPages.SURVEY in import_pages:
            self.import_wizard = SurveysImportPageWizard(self, self.openlog_connection)

        self.data_import_wizards.append(self.import_wizard)

        for data_import_wizard in self.data_import_wizards:
            self.addPage(data_import_wizard)

        self.confirmation_page = ConfirmationPageWizard(
            self, self.openlog_connection, self.data_import_wizards
        )

        # Wizard to confirm data import and commit database connection
        self.addPage(self.confirmation_page)

        # profile button appears on import_wizard page
        self.currentIdChanged.connect(self._update_buttons)
        # profile button is enabled if data source is set
        self.import_wizard.completeChanged.connect(self._update_buttons)

    def _update_buttons(self) -> None:
        """
        Update wizard buttons.
        """
        self.setOption(QWizard.HaveHelpButton, False)
        self.profile_btn.setEnabled(False)

        if isinstance(self.currentPage(), CollarsImportPageWizard) or isinstance(
            self.currentPage(), SurveysImportPageWizard
        ):

            self.setOption(QWizard.HaveHelpButton, True)
            self.setButton(QWizard.HelpButton, self.profile_btn)
            # appears only if data source is set
            if self.profile_enabled:
                self.profile_btn.setEnabled(True)
