"""
***************************************************************************
    qgssettingsentry.py
    ---------------------
    Date                 : April 2021
    Copyright            : (C) 2021 by Damiano Lombardi
    Email                : damiano@opengis.ch
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************
"""

from .metaenum import metaEnumFromValue
from qgis.core import (
    QgsSettings,
    QgsSettingsTree,
    QgsSettingsEntryBase,
    QgsLogger,
    Qgis,
)
import qgis  # required to get base class of enums


class PyQgsSettingsEntryEnumFlag(QgsSettingsEntryBase):
    """
    class PyQgsSettingsEntryEnumFlag
    An enum settings entry.
    since QGIS 3.20
    """

    def __init__(
        self,
        key,
        pluginName,
        defaultValue,
        description="",
        options=Qgis.SettingsOptions(),
    ):
        """
        Constructor for PyQgsSettingsEntryEnumFlag.

        :param key: argument specifies the final part of the settings key.
        :param pluginName: argument is either the plugin name or the settings tree parent element
        :param defaultValue: argument specifies the default value for the settings entry.
        :param description: argument specifies a description for the settings entry.
        """

        # TODO QGIS 4: rename pluginName arg to parent and key to name

        self.options = options
        defaultValueStr = ""
        self.__metaEnum = metaEnumFromValue(defaultValue)
        if self.__metaEnum is None or not self.__metaEnum.isValid():
            QgsLogger.debug(
                f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'"
            )
        else:
            if self.__metaEnum.isFlag():
                defaultValueStr = self.__metaEnum.valueToKeys(defaultValue)
            else:
                defaultValueStr = self.__metaEnum.valueToKey(defaultValue)
            self.__enumFlagClass = defaultValue.__class__

        if type(pluginName) is str:
            parent = QgsSettingsTree.createPluginTreeNode(pluginName)
        else:
            parent = pluginName
        super().__init__(key, parent, defaultValueStr, description, options)

    def metaEnum(self):
        return self.__metaEnum

    def typeId(self):
        """
        Defines a custom id since this class has not the same API as the cpp implementation
        """
        return "py-enumflag"

    def value(self, dynamicKeyPart=None):
        """
        Get settings value.

        :param dynamicKeyPart: argument specifies the dynamic part of the settings key.
        """
        if self.__metaEnum.isFlag():
            return QgsSettings().flagValue(
                self.key(dynamicKeyPart), self.defaultValue()
            )
        else:
            return QgsSettings().enumValue(
                self.key(dynamicKeyPart), self.defaultValue()
            )

    def valueWithDefaultOverride(self, defaultValueOverride, dynamicKeyPart=None):
        """
        Get settings value with a default value override.

        :param defaultValueOverride: argument if valid is used instead of the normal default value.
        :param dynamicKeyPart: argument specifies the dynamic part of the settings key.
        """
        if self.__metaEnum.isFlag():
            return QgsSettings().flagValue(
                self.key(dynamicKeyPart), defaultValueOverride
            )
        else:
            return QgsSettings().enumValue(
                self.key(dynamicKeyPart), defaultValueOverride
            )

    def defaultValue(self):
        """
        Get settings default value.
        """

        if self.__metaEnum is None or not self.__metaEnum.isValid():
            QgsLogger.debug(
                f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'"
            )
            return -1

        defaultValueString = self.defaultValueAsVariant()
        if self.__metaEnum.isFlag():
            (defaultValue, ok) = self.__metaEnum.keysToValue(defaultValueString)
        else:
            (defaultValue, ok) = self.__metaEnum.keyToValue(defaultValueString)
        if not ok:
            QgsLogger.debug(
                f"Invalid enum/flag key/s '{self.defaultValueAsVariant()}'."
            )
            return -1

        # cast to the enum class
        defaultValue = self.__enumFlagClass(defaultValue)
        return defaultValue

    def setValue(self, value, dynamicKeyPart: (list, str) = None):
        """
        Set settings value.

        :param value: the value to set for the setting.
        :param dynamicKeyPart: argument specifies the dynamic part of the settings key (a single one a string, or several as a list)
        """

        if self.__metaEnum is None or not self.__metaEnum.isValid():
            QgsLogger.debug(
                f"Invalid metaenum. Enum/Flag probably misses Q_ENUM/Q_FLAG declaration. Settings key: '{self.key()}'"
            )
            return False

        if self.options & Qgis.SettingsOption.SaveEnumFlagAsInt:
            enum_flag_key = int(value)
        else:
            if self.__metaEnum.isFlag():
                enum_flag_key = self.__metaEnum.valueToKeys(value)
            else:
                enum_flag_key = self.__metaEnum.valueToKey(value)
            if not enum_flag_key:
                QgsLogger.debug(f"Invalid enum/flag value '{value}'.")
                return False

        if type(dynamicKeyPart) is str:
            dynamicKeyPart = [dynamicKeyPart]
        elif dynamicKeyPart is None:
            dynamicKeyPart = []

        return super().setVariantValue(enum_flag_key, dynamicKeyPart)

    def settingsType(self):
        """
        Get the settings entry type.
        """
        return self.SettingsType.EnumFlag
