"""Switcher Bridge Response Messages."""

# fmt: off
from asyncio import AbstractEventLoop, Future, ensure_future
from binascii import hexlify
from socket import inet_ntoa
from struct import pack
from typing import Optional, Union

from ..consts import (ENCODING_CODEC, STATE_OFF, STATE_ON, STATE_RESPONSE_ON,
                      WAITING_TEXT)
from ..tools import convert_seconds_to_iso_time

# fmt: on


class SwitcherV2BroadcastMSG:
    """Represntation of the SwitcherV2 broadcast message.

    Args:
      loop: the event loop to perform actions in.
      message: the raw message from the device.

    Todo:
      * replace ``init_future`` attribute with ``get_init_future`` method.

    """

    def __init__(
        self, loop: AbstractEventLoop, message: Union[bytes, str]
    ) -> None:
        """Initialize the broadcast message."""
        self._loop = loop
        self._verified = self._validated = False
        self._power_consumption = 0
        self._electric_current = 0.0
        self._ip_address = WAITING_TEXT
        self._mac_address = WAITING_TEXT
        self._name = WAITING_TEXT
        self._device_id = WAITING_TEXT
        self._auto_off_set = WAITING_TEXT
        self._remaining_time_to_off = WAITING_TEXT
        self._init_future = loop.create_future()
        fixed_msg = (
            message
            if isinstance(message, bytes)
            else message.encode(ENCODING_CODEC)
        )
        ensure_future(self.initialize(fixed_msg), loop=loop)

    async def initialize(self, message: bytes) -> None:
        """Finish the initialization and update the future object.

        Args:
          message: the raw message from the device.

        """
        try:
            self._verified = (
                hexlify(message)[0:4].decode(ENCODING_CODEC) == "fef0"
                and len(message) == 165
            )
            if self._verified:
                temp_ip = hexlify(message)[152:160]
                ip_addr = int(
                    temp_ip[6:8] + temp_ip[4:6] + temp_ip[2:4] + temp_ip[0:2],
                    16,
                )
                self._ip_address = inet_ntoa(pack("<L", ip_addr))

                mac = hexlify(message)[160:172].decode(ENCODING_CODEC).upper()
                self._mac_address = (
                    mac[0:2]
                    + ":"
                    + mac[2:4]
                    + ":"
                    + mac[4:6]
                    + ":"
                    + mac[6:8]
                    + ":"
                    + mac[8:10]
                    + ":"
                    + mac[10:12]
                )

                self._name = (
                    message[42:74].decode(ENCODING_CODEC).rstrip("\x00")
                )

                self._device_id = hexlify(message)[36:42].decode(
                    ENCODING_CODEC
                )

                self._device_state = (
                    STATE_ON
                    if hexlify(message)[266:270].decode(ENCODING_CODEC)
                    == STATE_RESPONSE_ON
                    else STATE_OFF
                )

                temp_auto_off_set = hexlify(message)[310:318]
                temp_auto_off_set_seconds = int(
                    temp_auto_off_set[6:8]
                    + temp_auto_off_set[4:6]
                    + temp_auto_off_set[2:4]
                    + temp_auto_off_set[0:2],
                    16,
                )
                self._auto_off_set = await convert_seconds_to_iso_time(
                    self._loop, temp_auto_off_set_seconds
                )

                if self._device_state == STATE_ON:
                    temp_power = hexlify(message)[270:278]
                    self._power_consumption = int(
                        temp_power[2:4] + temp_power[0:2], 16
                    )
                    self._electric_current = round(
                        (self._power_consumption / float(220)), 1
                    )

                    temp_remaining_time = hexlify(message)[294:302]
                    temp_remaining_time_seconds = int(
                        temp_remaining_time[6:8]
                        + temp_remaining_time[4:6]
                        + temp_remaining_time[2:4]
                        + temp_remaining_time[0:2],
                        16,
                    )
                    self._remaining_time_to_off = (
                        await convert_seconds_to_iso_time(
                            self._loop, temp_remaining_time_seconds
                        )
                    )

            self._validated = True
            self.init_future.set_result(self)
        except (ValueError, IndexError, RuntimeError) as ex:
            self.init_future.set_exception(ex)
        return None

    @property
    def verified(self) -> bool:
        """bool: Return whether or not the message is a SwitcherV2 message."""
        return self._verified if self._validated else self._validated

    @property
    def ip_address(self) -> str:
        """str: Return the ip address."""
        return self._ip_address

    @property
    def mac_address(self) -> str:
        """str: Return the mac address."""
        return self._mac_address

    @property
    def name(self) -> str:
        """str: Return the device name."""
        return self._name

    @property
    def device_id(self) -> str:
        """str: Return the device id."""
        return self._device_id

    @property
    def power(self) -> int:
        """int: Return the power consumptionin watts."""
        return self._power_consumption

    @property
    def device_state(self) -> str:
        """str: Return the state of the device."""
        return self._device_state

    @property
    def remaining_time_to_off(self) -> Optional[str]:
        """str: Return the time left to auto-off."""
        return self._remaining_time_to_off

    @property
    def current(self) -> float:
        """float: Return the power consumptionin amps."""
        return self._electric_current

    @property
    def auto_off_set(self) -> str:
        """str: Return the auto-off configuration value."""
        return self._auto_off_set

    @property
    def init_future(self) -> Future:
        """asyncio.Future: Return the future of the device initialization."""
        return self._init_future
