from pathlib import Path

from qgis.core import (
    NULL,
    Qgis,
    QgsApplication,
    QgsProviderConnectionException,
    QgsProviderRegistry,
)
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, pyqtSignal
from qgis.PyQt.QtGui import QCursor, QIcon
from qgis.PyQt.QtWidgets import (
    QCheckBox,
    QDialog,
    QHBoxLayout,
    QMessageBox,
    QTableWidgetItem,
    QToolButton,
    QWidget,
)

from plui_versionning.core.utils import catch_postgres_exception
from plui_versionning.gui.dlg_add_style import AddStyleDialog
from plui_versionning.toolbelt import PlgLogger, PlgOptionsManager


class ManageStylesDialog(QDialog):
    # Signal pour rafraichir le tableau dans la gestion des styles lorsqu'on change de procédure
    refreshStyles = pyqtSignal(object)

    def __init__(self, id_proc: int = None, parent: QWidget = None, *args, **kwds):
        """
        QDialog Gérer les styles
        """
        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_proc  # Procédure chargée dans le dashboard
        self.dlg_add_style = None
        self.refreshStyles.connect(self.load_styles)
        self.btn_ajouter_style.clicked.connect(self.add_style)
        self.load_styles(id_proc)

    def add_style(self):
        """Shows dialog to add style"""
        self.dlg_add_style = AddStyleDialog(id_proc=self.id_procedure, parent=self)
        self.dlg_add_style.addStyle.connect(self.refreshStyles)
        self.dlg_add_style.show()

    def list_styles(self):
        query = """
        select vps.id, vps.nom_thematique, vps.format, vps.procedure_plui, vps.cnig
        from \"{0}\".v_pluiv_styles vps
        left join \"{0}\".v_pluiv_procedures vproc on vps.procedure_plui = vproc.procedure_plui
        {where_id_proc}
        """.format(
            self.db_schema_name,
            where_id_proc=(
                f"where vproc.id = {self.id_procedure}"
                if self.id_procedure is not None
                else ""
            ),
        )
        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 get_style(self, id_style):
        query = """
        select id, nom_thematique, format, procedure_plui, cnig from \"{}\".v_pluiv_styles
        where id={}
        """.format(
            self.db_schema_name, id_style
        )
        md = QgsProviderRegistry.instance().providerMetadata("postgres")
        conn = md.createConnection(self.db_connection_uri, {})
        try:
            result = conn.executeSql(query)
            if result:
                return result[0]
        except QgsProviderConnectionException as e:
            self.log(message=e, log_level=Qgis.Critical, push=True)

    def load_styles(self, id_procedure=None):
        self.table_styles.clearContents()
        self.table_styles.setRowCount(0)
        if id_procedure != self.id_procedure and self.dlg_add_style is not None:
            # Refresh des thématiques si la procédure a changé et que le dialogue d'ajout des styles est ouvert
            self.dlg_add_style.refreshThematiques.emit(id_procedure)
        self.id_procedure = id_procedure
        self.table_styles.setColumnHidden(2, self.id_procedure is not None)

        styles = self.list_styles()
        if styles:
            for s in styles:
                column = 0
                self.table_styles.insertRow(self.table_styles.rowCount())
                thematique_item = QTableWidgetItem(s[1])
                thematique_item.setData(Qt.UserRole, s[0])
                self.table_styles.setItem(
                    self.table_styles.rowCount() - 1, column, thematique_item
                )
                column += 1
                format_item = QTableWidgetItem(s[2])
                format_item.setData(Qt.UserRole, s[0])
                self.table_styles.setItem(
                    self.table_styles.rowCount() - 1, column, format_item
                )
                column += 1
                if self.id_procedure is None:
                    procedure_item = QTableWidgetItem(s[3])
                    procedure_item.setData(Qt.UserRole, s[0])
                    self.table_styles.setItem(
                        self.table_styles.rowCount() - 1, column, procedure_item
                    )
                column += 1
                wdg_cnig = QWidget()
                hl = QHBoxLayout()
                cb_cnig = QCheckBox()
                cb_cnig.setEnabled(False)
                cb_cnig.setCheckState(Qt.Checked if s[4] else Qt.Unchecked)
                hl.addWidget(cb_cnig)
                hl.setAlignment(Qt.AlignCenter)
                hl.setContentsMargins(0, 0, 0, 0)
                wdg_cnig.setLayout(hl)
                self.table_styles.setCellWidget(
                    self.table_styles.rowCount() - 1, column, wdg_cnig
                )
                column += 1

                if not s[4] and not self.is_finished_procedure(s[3]):
                    wdg_delete = QWidget()
                    hl = QHBoxLayout()
                    icon_delete = QIcon(
                        QgsApplication.iconPath("mActionDeleteSelected.svg")
                    )
                    btn_delete = QToolButton()
                    btn_delete.setIcon(icon_delete)
                    btn_delete.setToolTip("Supprimer le style")
                    btn_delete.setAutoRaise(True)
                    btn_delete.setCursor(QCursor(Qt.PointingHandCursor))
                    id_style = self.table_styles.item(
                        self.table_styles.rowCount() - 1, 1
                    ).data(Qt.UserRole)
                    btn_delete.clicked.connect(
                        lambda *args, id_style=id_style: self.delete_style(id_style)
                    )
                    hl.addWidget(btn_delete)
                    hl.setAlignment(Qt.AlignCenter)
                    hl.setContentsMargins(0, 0, 0, 0)
                    wdg_delete.setLayout(hl)
                    self.table_styles.setCellWidget(
                        self.table_styles.rowCount() - 1, column, wdg_delete
                    )

    def delete_style(self, id_style):
        style = self.get_style(id_style)
        thematique = style[1]
        procedure = style[3]
        response = QMessageBox().question(
            self,
            "Confirmer la suppression du style",
            f"Êtes-vous sûr de vouloir supprimer le style de la thématique {thematique} pour la procédure {procedure} ?",
        )

        if response == QMessageBox.Yes:
            query = 'select "{}".qgis_supprimer_style({})'.format(
                self.db_schema_name, id_style
            )
            md = QgsProviderRegistry.instance().providerMetadata("postgres")
            conn = md.createConnection(self.db_connection_uri, {})
            try:
                conn.executeSql(query)
                self.log(
                    message=f"Le style de la thématique {thematique} pour la procédure {procedure} a été supprimé",
                    log_level=Qgis.Success,
                    push=True,
                )
                self.load_styles(self.id_procedure)
            except QgsProviderConnectionException as e:
                self.log(
                    message=catch_postgres_exception(str(e)),
                    log_level=Qgis.Critical,
                    push=True,
                )

    def is_finished_procedure(self, procedure_plui: str) -> bool:
        """Renvoie vrai si la procédure a une date de fin de procédure"""
        query = """
            (SELECT pp.id, pp.procedure_plui, pp.datefin_proc
            FROM {}.v_pluiv_procedures pp
            WHERE procedure_plui = '{}'
            )
        """.format(
            self.db_schema_name, procedure_plui
        )
        md = QgsProviderRegistry.instance().providerMetadata("postgres")
        conn = md.createConnection(self.db_connection_uri, {})
        try:
            result = conn.executeSql(query)
            if result:
                return result[0][2] != NULL
        except QgsProviderConnectionException as e:
            self.log(message=e, log_level=Qgis.Critical, push=True)
        return False
