from pathlib import Path

from qgis.core import NULL, Qgis, QgsProviderConnectionException, QgsProviderRegistry
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtGui import QCloseEvent, QColor
from qgis.PyQt.QtWidgets import (
    QCheckBox,
    QDialog,
    QHBoxLayout,
    QMessageBox,
    QTableWidgetItem,
    QWidget,
)

from plui_versionning.gui.dlg_terminate_procedure import TerminateProcedureDialog
from plui_versionning.toolbelt import PlgLogger, PlgOptionsManager


class PrepareProcedureDialog(QDialog):
    def __init__(self, id_procedure: int, parent: QWidget = None, *args, **kwds):
        """
        QDialog Préparer une procédure
        """
        super().__init__(parent, *args, **kwds)
        self.log = PlgLogger().log

        # DB connection
        self.db_connection_uri = (
            PlgOptionsManager().get_plg_settings().db_connection_uri
        )
        self.db_schema_name = PlgOptionsManager().get_plg_settings().db_schema_name

        uic.loadUi(Path(__file__).parent / f"{Path(__file__).stem}.ui", self)

        self.id_procedure = id_procedure  # Procédure courante
        self.procedure_plui = self.get_procedure()
        self.change = (
            False  # pour savoir si l'utilisateur a fait un changement dans l'interface
        )
        self.lbl_procedure_value.setText(self.procedure_plui)
        self.btn_terminer.clicked.connect(self.terminate)
        self.btn_terminer.setEnabled(not self.is_procedure_terminated())

        self.load_projets_procedure()

    def list_projets_procedure(self):
        query = """
            select id_projet, nom_thematique, categorie, nom_projet, id_version, embarque from {}.v_pluiv_projets_procedure
            where procedure_plui = '{}'
        """.format(
            self.db_schema_name, self.procedure_plui
        )
        md = QgsProviderRegistry.instance().providerMetadata("postgres")
        conn = md.createConnection(self.db_connection_uri, {})
        try:
            result = conn.executeSql(query)
            if result:
                return result
        except QgsProviderConnectionException as e:
            self.log(message=e, log_level=Qgis.Critical, push=True)

    def load_projets_procedure(self):
        self.table_projets_procedure.clearContents()
        self.table_projets_procedure.setRowCount(0)

        projets_procedure = self.list_projets_procedure()
        if projets_procedure:
            for p in projets_procedure:
                self.table_projets_procedure.insertRow(
                    self.table_projets_procedure.rowCount()
                )
                thematique_item = QTableWidgetItem(f"{p[1]}")
                thematique_item.setData(Qt.UserRole, p[0])
                thematique_item.setFlags(thematique_item.flags() ^ Qt.ItemIsEditable)
                self.table_projets_procedure.setItem(
                    self.table_projets_procedure.rowCount() - 1, 0, thematique_item
                )
                categorie_item = QTableWidgetItem(f"{p[2]}")
                categorie_item.setData(Qt.UserRole, p[0])
                categorie_item.setFlags(categorie_item.flags() ^ Qt.ItemIsEditable)
                self.table_projets_procedure.setItem(
                    self.table_projets_procedure.rowCount() - 1, 1, categorie_item
                )
                projet_item = QTableWidgetItem(f"{p[3]}")
                projet_item.setData(Qt.UserRole, p[0])
                projet_item.setFlags(projet_item.flags() ^ Qt.ItemIsEditable)
                self.table_projets_procedure.setItem(
                    self.table_projets_procedure.rowCount() - 1, 2, projet_item
                )
                version_item = QTableWidgetItem(f"{p[4] if p[4] != NULL else ''}")
                version_item.setData(Qt.UserRole, p[0])
                version_item.setFlags(version_item.flags() ^ Qt.ItemIsEditable)
                if p[4] == NULL:
                    version_item.setBackground(QColor(255, 0, 0, 50))
                self.table_projets_procedure.setItem(
                    self.table_projets_procedure.rowCount() - 1, 3, version_item
                )
                wdg_embarque = QWidget()
                hl = QHBoxLayout()
                cb_embarque = QCheckBox()
                cb_embarque.setCheckState(Qt.Checked if p[5] else Qt.Unchecked)
                cb_embarque.setEnabled(p[4] != NULL)
                cb_embarque.stateChanged.connect(lambda: self.checkboxChanged())
                hl.addWidget(cb_embarque)
                hl.setAlignment(Qt.AlignCenter)
                hl.setContentsMargins(0, 0, 0, 0)
                wdg_embarque.checkbox = cb_embarque
                wdg_embarque.setLayout(hl)
                self.table_projets_procedure.setCellWidget(
                    self.table_projets_procedure.rowCount() - 1, 4, wdg_embarque
                )
                if p[4] == NULL:
                    thematique_item.setFlags(Qt.NoItemFlags)
                    categorie_item.setFlags(Qt.NoItemFlags)
                    projet_item.setFlags(Qt.NoItemFlags)
                    version_item.setFlags(Qt.NoItemFlags)
                self.table_projets_procedure.resizeColumnsToContents()

    def checkboxChanged(self):
        self.change = True

    def apply(self):
        embarques, not_embarques = [], []
        for row in range(self.table_projets_procedure.rowCount()):
            id = self.table_projets_procedure.item(row, 0).data(Qt.UserRole)
            wdg_embarque = self.table_projets_procedure.cellWidget(row, 4)
            item_embarque = wdg_embarque.checkbox
            embarque = item_embarque.isChecked()
            if embarque:
                embarques.append(id)
            else:
                not_embarques.append(id)
        self.set_embarque(True, embarques)
        self.set_embarque(False, not_embarques)
        self.change = False

    def set_embarque(self, embarque: bool, ids: list[int]):
        if not ids:
            return
        query = """
        update \"{}\".pluiv_projets
            set embarque = '{}'
        where id = any(array{})
        """.format(
            self.db_schema_name, embarque, ids
        )
        md = QgsProviderRegistry.instance().providerMetadata("postgres")
        conn = md.createConnection(self.db_connection_uri, {})
        try:
            conn.executeSql(query)
        except QgsProviderConnectionException as e:
            self.log(message=e, log_level=Qgis.Critical, push=True)

    def terminate(self):
        """Shows dialog to terminate current procedure"""
        self.apply()
        dlg_terminate_proc = TerminateProcedureDialog(
            id_procedure=self.id_procedure, parent=self
        )
        dlg_terminate_proc.exec_()

    def closeEvent(self, event: QCloseEvent) -> None:
        if not self.is_procedure_terminated() and self.change:
            # Demande pour appliquer les changements effectués lors de la fermeture de la fenêtre
            response = QMessageBox().question(
                self,
                "Sauvegarder les changements",
                "Voulez-vous sauvegarder les changements effectués ?",
            )
            if response == QMessageBox.Yes:
                self.apply()
        return super().closeEvent(event)

    def get_procedure(self) -> str:
        """Return procedure_plui in pluiv_procedures table regarding id"""
        query = (
            'select procedure_plui from "{}".v_pluiv_procedures where id = {}'.format(
                self.db_schema_name, self.id_procedure
            )
        )
        md = QgsProviderRegistry.instance().providerMetadata("postgres")
        conn = md.createConnection(self.db_connection_uri, {})
        try:
            result = conn.executeSql(query)
            return result[0][0]
        except QgsProviderConnectionException as e:
            self.log(message=e, log_level=Qgis.Critical, push=True)
        return None

    def is_procedure_terminated(self) -> bool:
        """Return true if procedure has datefin_proc != NULL"""
        query = 'select datefin_proc from "{}".v_pluiv_procedures where id = {}'.format(
            self.db_schema_name, self.id_procedure
        )
        md = QgsProviderRegistry.instance().providerMetadata("postgres")
        conn = md.createConnection(self.db_connection_uri, {})
        try:
            result = conn.executeSql(query)
            return result[0][0] != NULL
        except QgsProviderConnectionException as e:
            self.log(message=e, log_level=Qgis.Critical, push=True)
        return False
