"""Operating flag or Extended Property for all device types."""
from ..address import Address
from ..constants import PropertyType
from ..subscriber_base import SubscriberBase


class DeviceFlagBase(SubscriberBase):
    """Operating flag or Extended Property."""

    def __init__(
        self,
        address,
        topic_prefix,
        name,
        value_type: type,
        is_reversed=False,
        is_read_only=False,
        prop_type=PropertyType.STANDARD,
    ):
        """Init the DeviceFlag class."""
        self._address = Address(address)
        topic = f"{self._address.id}.{topic_prefix}.{name}"
        super().__init__(topic)
        self._name = name
        self._value = None
        self._value_type = value_type
        self._new_value = None
        self._is_loaded = False
        self._reversed = is_reversed
        self._read_only = is_read_only
        self._prop_type = PropertyType(prop_type)

    @property
    def name(self):
        """Return the flag name."""
        return self._name

    @property
    def value(self):
        """Return the value of the flag."""
        return self._value

    @property
    def new_value(self):
        """Return the new value of the flag."""
        return self._new_value

    @new_value.setter
    def new_value(self, value):
        """Set the new value of the flag.

        This is the primary method to set the value of the flag.
        It sets the `new_value` property and the `is_dirty` property.
        """
        if self._read_only:
            return

        if self._value_type is bool and self._reversed:
            value = not value

        if value != self._value and value is not None:
            self._new_value = self._value_type(value)
        else:
            self._new_value = None

    @property
    def value_type(self):
        """Return the property type."""
        return self._value_type

    @property
    def is_dirty(self):
        """Return if the Operating flag has been changed."""
        return self._new_value is not None

    @property
    def is_read_only(self):
        """Return the read only flag."""
        return self._read_only

    @is_read_only.setter
    def is_read_only(self, value: bool) -> None:
        """Set the read only flag of the property."""
        self._read_only = bool(value)

    @property
    def is_loaded(self):
        """Return if the Operating flag has been loaded."""
        return self._is_loaded

    @property
    def is_reversed(self):
        """Return if the device flag is reverse of this value."""
        return self._reversed

    @property
    def property_type(self):
        """Return the property type (Standard, Advanced, Derived or Hidden)."""
        return self._prop_type

    @property_type.setter
    def property_type(self, value: PropertyType):
        """Set the propoerty type for this property."""
        self._prop_type = PropertyType(value)

    def set_value(self, value):
        """Load the flag from the device value.

        Only use this method to update the value of the flag from the value
        of the device.

        This method updates the `is_loaded` property and clears the `new value` and
        `is_dirty` properties.
        """
        if self._value_type is bool and self._reversed:
            value = not value
        update_value = (
            self._value_type(value) if value is not None else self._value_type(0)
        )
        self._new_value = None
        self._is_loaded = True
        is_changed = update_value != self._value
        self._value = update_value
        if is_changed:
            self._call_subscribers(name=self._name, value=self._value)
