from qgis.PyQt import QtCore
from qgis.PyQt.QtCore import QVariant
from qgis.PyQt.QtGui import QFont, QStandardItemModel


class StringMapTableModel(QStandardItemModel):
    KEY_ROW = 0
    VALUE_ROW = 1

    def __init__(self, parent=None, key_label: str = "", val_label: str = "") -> None:
        """
        QStandardItemModel for string map display

        Args:
            parent: QWidget
        """
        super().__init__(parent)
        self.setVerticalHeaderLabels([key_label, val_label])

    def flags(self, index: QtCore.QModelIndex) -> QtCore.Qt.ItemFlags:
        """
        Override QStandardItemModel flags to remove edition for key

        Args:
            index: QModelIndex

        Returns: index flags

        """
        flags = super().flags(index)
        if index.row() == self.KEY_ROW:
            flags = flags & QtCore.Qt.ItemIsEditable
        return flags

    def data(
        self, index: QtCore.QModelIndex, role: int = QtCore.Qt.DisplayRole
    ) -> QVariant:
        """
        Override QStandardItemModel data() for font of expected column

        Args:
            index: QModelIndex
            role: Qt role

        Returns: QVariant

        """
        result = super().data(index, role)
        if role == QtCore.Qt.FontRole and index.row() == self.KEY_ROW:
            result = QFont()
            result.setBold(True)

        return result

    def set_string_map(self, map: {str: str}) -> None:
        """
        Define current string map

        Args:
            map: string map
        """

        while self.columnCount():
            self.removeColumn(0)

        for key, val in map.items():
            col = self._get_or_create_key(key)
            self.setData(self.index(self.VALUE_ROW, col), val)

    def get_string_map(self) -> {str: str}:
        """
        Get current string map

        Returns: current string map

        """
        result = {}
        for i in range(self.columnCount()):
            column = str(self.data(self.index(self.KEY_ROW, i)))
            mapping = self.data(self.index(self.VALUE_ROW, i))
            if column and mapping:
                result[column] = str(mapping)
        return result

    def _get_or_create_key(self, key: str) -> int:
        """
        Get or create key

        Args:
            key: key

        Returns: column index

        """
        column = self._get_key_col(key)
        if column == -1:
            self.insertColumn(self.columnCount())
            column = self.columnCount() - 1
            self.setData(self.index(self.KEY_ROW, column), key)
        return column

    def _get_key_col(self, key: str) -> int:
        """
        Get expected key column index (-1 if expected key not available)

        Args:
            key: (str) expected key

        Returns: expected key column index (-1 if expected key not available)

        """
        column = -1
        for i in range(self.columnCount()):
            val = str(self.data(self.index(self.KEY_ROW, i)))
            if val == key:
                column = i
        return column
