from dataclasses import dataclass

from qgis.PyQt import QtCore
from qgis.PyQt.QtCore import QVariant
from qgis.PyQt.QtGui import QColor, QStandardItemModel
from qgis.PyQt.QtWidgets import QComboBox, QStyledItemDelegate, QWidget
from xplordb.import_ddl import ImportDDL


@dataclass
class User:
    name: str
    role: str
    trigram: str = ""
    password: str = ""
    password_confirmation: str = ""


class RoleItemDelegate(QStyledItemDelegate):
    def __init__(self, parent) -> None:
        """
        QStyledItemDelegate for xplordb role definition

        Args:
            parent:
        """
        super().__init__(parent)

    def createEditor(self, parent, option, index) -> QWidget:
        """
        Create a QComboBox for xplordb role definition

        Args:
            parent: QWidget
            option: QStyleOptionViewItem
            index: QModelIndex

        Returns: QComboBox with available xplordb roles

        """
        editor = QComboBox(parent)
        editor.addItems(ImportDDL.xplordb_roles())
        return editor


class UserTableModel(QStandardItemModel):
    NAME_COL = 0
    TRIGRAM_COL = 1
    ROLE_COL = 2
    PASSWORD_COL = 3
    PASSWORD_CONFIRMATION_COL = 4

    def __init__(self, parent=None) -> None:
        """
        QStandardItemModel for user display and creation

        Args:
            parent: QWidget
        """
        super(UserTableModel, self).__init__(parent)
        self.setHorizontalHeaderLabels(
            ["Name", "Trigram", "Role", "Password", "Confirm password"]
        )

    def data(
        self, index: QtCore.QModelIndex, role: int = QtCore.Qt.DisplayRole
    ) -> QVariant:
        """
        Override QStandardItemModel data() for automatic trigram definition
        and background color change in case of invalid password confirmation

        Args:
            index:
            role:

        Returns:

        """
        result = super().data(index, role)

        if role == QtCore.Qt.DisplayRole:
            # For TRIGRAM_COL define default value from name if none set
            if index.column() == self.TRIGRAM_COL and not result:
                name = str(self.data(index.sibling(index.row(), self.NAME_COL), role))
                if name:
                    result = name[0 : min(len(name), 3)]
        if role == QtCore.Qt.BackgroundRole:
            # For PASSWORD_CONFIRMATION_COL check if value is correct
            if index.column() == self.PASSWORD_CONFIRMATION_COL:
                password = str(self.data(index.sibling(index.row(), self.PASSWORD_COL)))
                password_confirm = str(self.data(index, QtCore.Qt.DisplayRole))
                if password_confirm != password:
                    result = QColor("yellow")

        return result

    def add_user(self, user: User = None) -> None:
        """
        Add a user row in QStandardItemModel

        Args:
            user: option User for row definition
        """
        self.insertRow(self.rowCount())
        if user:
            self._set_user_data(self.rowCount() - 1, user)

    def get_user_list(self) -> [User]:
        """
        Get users list define in QStandardItemModel

        Returns: List of user with valid name and valid password confirmation

        """
        result = []
        for i in range(self.rowCount()):
            name = str(self.data(self.index(i, self.NAME_COL)))
            trigram = str(self.data(self.index(i, self.TRIGRAM_COL)))
            role = str(self.data(self.index(i, self.ROLE_COL)))
            password = str(self.data(self.index(i, self.PASSWORD_COL)))
            password_confirmation = str(
                self.data(self.index(i, self.PASSWORD_CONFIRMATION_COL))
            )
            result.append(
                User(
                    name=name,
                    trigram=trigram,
                    role=role,
                    password=password,
                    password_confirmation=password_confirmation,
                )
            )
        return result

    def _set_user_data(self, row: int, user: User) -> None:
        """
        Define QStandardItemModel data from User

        Args:
            row: model row
            user: User
        """
        self.setData(self.index(row, self.NAME_COL), user.name)
        self.setData(self.index(row, self.TRIGRAM_COL), user.trigram)
        self.setData(self.index(row, self.ROLE_COL), user.role)
        self.setData(self.index(row, self.PASSWORD_COL), user.password)
