import logging
import json
from .message import (
    MessageQuery,
    MessageSwitchDisplay,
    MessageNewProtocolQuery,
    MessageACResponse,
    MessageGeneralSet,
    MessageNewProtocolSet,
    MessagePowerQuery,
    MessageSubProtocolQuery,
    MessageSubProtocolSet
)
try:
    from enum import StrEnum
except ImportError:
    from ...backports.enum import StrEnum
from ...core.device import MiedaDevice

_LOGGER = logging.getLogger(__name__)


class DeviceAttributes(StrEnum):
    prompt_tone = "prompt_tone"
    power = "power"
    mode = "mode"
    target_temperature = "target_temperature"
    fan_speed = "fan_speed"
    swing_vertical = "swing_vertical"
    swing_horizontal = "swing_horizontal"
    boost_mode = "boost_mode"
    smart_eye = "smart_eye"
    dry = "dry"
    eco_mode = "eco_mode"
    aux_heating = "aux_heating"
    sleep_mode = "sleep_mode"
    natural_wind = "natural_wind"
    temp_fahrenheit = "temp_fahrenheit"
    screen_display = "screen_display"
    screen_display_new = "screen_display_new"
    full_dust = "full_dust"
    frost_protect = "frost_protect"
    comfort_mode = "comfort_mode"
    indoor_temperature = "indoor_temperature"
    outdoor_temperature = "outdoor_temperature"
    indirect_wind = "indirect_wind"
    indoor_humidity = "indoor_humidity"
    breezeless = "breezeless"
    fresh_air_power = "fresh_air_power"
    fresh_air_fan_speed = "fresh_air_fan_speed"
    fresh_air_mode = "fresh_air_mode"
    fresh_air_1 = "fresh_air_1"
    fresh_air_2 = "fresh_air_2"
    total_energy_consumption = "total_energy_consumption"
    current_energy_consumption = "current_energy_consumption"
    realtime_power = "realtime_power"


class MideaACDevice(MiedaDevice):
    _fresh_air_fan_speeds = {
        0: "Off", 20: "Silent", 40: "Low", 60: "Medium", 80: "High", 100: "Full"
    }
    _fresh_air_fan_speeds_rev = dict(reversed(_fresh_air_fan_speeds.items()))

    def __init__(
            self,
            name: str,
            device_id: int,
            ip_address: str,
            port: int,
            token: str,
            key: str,
            protocol: int,
            model: str,
            customize: str
    ):
        super().__init__(
            name=name,
            device_id=device_id,
            device_type=0xAC,
            ip_address=ip_address,
            port=port,
            token=token,
            key=key,
            protocol=protocol,
            model=model,
            attributes={
                DeviceAttributes.prompt_tone: True,
                DeviceAttributes.power: False,
                DeviceAttributes.mode: 0,
                DeviceAttributes.target_temperature: 24.0,
                DeviceAttributes.fan_speed: 102,
                DeviceAttributes.swing_vertical: False,
                DeviceAttributes.swing_horizontal: False,
                DeviceAttributes.smart_eye: False,
                DeviceAttributes.dry: False,
                DeviceAttributes.aux_heating: False,
                DeviceAttributes.boost_mode: False,
                DeviceAttributes.sleep_mode: False,
                DeviceAttributes.frost_protect: False,
                DeviceAttributes.comfort_mode: False,
                DeviceAttributes.eco_mode: False,
                DeviceAttributes.natural_wind: False,
                DeviceAttributes.temp_fahrenheit: False,
                DeviceAttributes.screen_display: False,
                DeviceAttributes.screen_display_new: False,
                DeviceAttributes.full_dust: False,
                DeviceAttributes.indoor_temperature: None,
                DeviceAttributes.outdoor_temperature: None,
                DeviceAttributes.indirect_wind: False,
                DeviceAttributes.indoor_humidity: None,
                DeviceAttributes.breezeless: False,
                DeviceAttributes.total_energy_consumption: None,
                DeviceAttributes.current_energy_consumption: None,
                DeviceAttributes.realtime_power: None,
                DeviceAttributes.fresh_air_power: False,
                DeviceAttributes.fresh_air_fan_speed: 0,
                DeviceAttributes.fresh_air_mode: None,
                DeviceAttributes.fresh_air_1: None,
                DeviceAttributes.fresh_air_2: None,
            })
        self._fresh_air_version = None
        self._default_temperature_step = 0.5
        self._temperature_step = None
        self._used_subprotocol = False
        self._bb_sn8_flag = False
        self._bb_timer = False
        self._power_analysis_method = None
        self._default_power_analysis_method = 1
        self.set_customize(customize)

    @property
    def temperature_step(self):
        return self._temperature_step

    @property
    def fresh_air_fan_speeds(self):
        return list(MideaACDevice._fresh_air_fan_speeds.values())

    def build_query(self):
        if self._used_subprotocol:
            return [
                MessageSubProtocolQuery(self._device_protocol_version, 0x10),
                MessageSubProtocolQuery(self._device_protocol_version, 0x11),
                MessageSubProtocolQuery(self._device_protocol_version, 0x30)
            ]
        return [
            MessageQuery(self._device_protocol_version),
            MessageNewProtocolQuery(self._device_protocol_version),
            MessagePowerQuery(self._device_protocol_version)
        ]

    def process_message(self, msg):
        message = MessageACResponse(msg, self._power_analysis_method)
        _LOGGER.debug(f"[{self.device_id}] Received: {message}")
        new_status = {}
        has_fresh_air = False
        if hasattr(message, "used_subprotocol"):
            self._used_subprotocol = True
            if hasattr(message, "sn8_flag"):
                self._bb_sn8_flag = message.sn8_flag
            if hasattr(message, "timer"):
                self._bb_timer = message.timer
        for status in self._attributes.keys():
            if hasattr(message, str(status)):
                value = getattr(message, str(status))
                if status == DeviceAttributes.fresh_air_power:
                    has_fresh_air = True
                self._attributes[status] = value
                new_status[str(status)] = self._attributes[status]
        if has_fresh_air:
            if self._attributes[DeviceAttributes.fresh_air_power]:
                for k, v in MideaACDevice._fresh_air_fan_speeds_rev.items():
                    if self._attributes[DeviceAttributes.fresh_air_fan_speed] > k:
                        break
                    else:
                        self._attributes[DeviceAttributes.fresh_air_mode] = v
            else:
                self._attributes[DeviceAttributes.fresh_air_mode] = "Off"
            new_status[DeviceAttributes.fresh_air_mode.value] = self._attributes[DeviceAttributes.fresh_air_mode]
        if not self._attributes[DeviceAttributes.power] or \
                (DeviceAttributes.swing_vertical in new_status and self._attributes[DeviceAttributes.swing_vertical]):
            self._attributes[DeviceAttributes.indirect_wind] = False
            new_status[DeviceAttributes.indirect_wind.value] = False
        if not self._attributes[DeviceAttributes.power]:
            self._attributes[DeviceAttributes.screen_display] = False
            new_status[DeviceAttributes.screen_display.value] = False
        if self._attributes[DeviceAttributes.fresh_air_1] is not None:
            self._fresh_air_version = DeviceAttributes.fresh_air_1
        elif self._attributes[DeviceAttributes.fresh_air_2] is not None:
            self._fresh_air_version = DeviceAttributes.fresh_air_2
        return new_status

    def make_message_set(self):
        message = MessageGeneralSet(self._device_protocol_version)
        message.power = self._attributes[DeviceAttributes.power]
        message.prompt_tone = self._attributes[DeviceAttributes.prompt_tone]
        message.mode = self._attributes[DeviceAttributes.mode]
        message.target_temperature = self._attributes[DeviceAttributes.target_temperature]
        message.fan_speed = self._attributes[DeviceAttributes.fan_speed]
        message.swing_vertical = self._attributes[DeviceAttributes.swing_vertical]
        message.swing_horizontal = self._attributes[DeviceAttributes.swing_horizontal]
        message.boost_mode = self._attributes[DeviceAttributes.boost_mode]
        message.smart_eye = self._attributes[DeviceAttributes.smart_eye]
        message.dry = self._attributes[DeviceAttributes.dry]
        message.eco_mode = self._attributes[DeviceAttributes.eco_mode]
        message.aux_heating = self._attributes[DeviceAttributes.aux_heating]
        message.sleep_mode = self._attributes[DeviceAttributes.sleep_mode]
        message.natural_wind = self._attributes[DeviceAttributes.natural_wind]
        message.temp_fahrenheit = self._attributes[DeviceAttributes.temp_fahrenheit]
        message.frost_protect = self._attributes[DeviceAttributes.frost_protect]
        message.comfort_mode = self._attributes[DeviceAttributes.comfort_mode]
        return message

    def make_subptotocol_message_set(self):
        message = MessageSubProtocolSet(self._device_protocol_version)
        message.power = self._attributes[DeviceAttributes.power]
        message.prompt_tone = self._attributes[DeviceAttributes.prompt_tone]
        message.aux_heating = self._attributes[DeviceAttributes.aux_heating]
        message.mode = self._attributes[DeviceAttributes.mode]
        message.target_temperature = self._attributes[DeviceAttributes.target_temperature]
        message.fan_speed = self._attributes[DeviceAttributes.fan_speed]
        message.boost_mode = self._attributes[DeviceAttributes.boost_mode]
        message.dry = self._attributes[DeviceAttributes.dry]
        message.eco_mode = self._attributes[DeviceAttributes.eco_mode]
        message.sleep_mode = self._attributes[DeviceAttributes.sleep_mode]
        message.sn8_flag = self._bb_sn8_flag
        message.timer = self._bb_timer
        return message

    def make_message_uniq_set(self):
        if self._used_subprotocol:
            message = self.make_subptotocol_message_set()
        else:
            message = self.make_message_set()
        return message

    def set_attribute(self, attr, value):
        # if nat a sensor
        message = None
        if attr not in [DeviceAttributes.indoor_temperature,
                        DeviceAttributes.outdoor_temperature,
                        DeviceAttributes.indoor_humidity,
                        DeviceAttributes.full_dust,
                        DeviceAttributes.total_energy_consumption,
                        DeviceAttributes.current_energy_consumption,
                        DeviceAttributes.realtime_power]:
            if attr == DeviceAttributes.prompt_tone:
                self._attributes[DeviceAttributes.prompt_tone] = value
                self.update_all({DeviceAttributes.prompt_tone.value: value})
            elif attr == DeviceAttributes.screen_display:
                if self._attributes[DeviceAttributes.screen_display_new]:
                    message = MessageNewProtocolSet(self._device_protocol_version)
                    message.screen_display = value
                    message.prompt_tone = self._attributes[DeviceAttributes.prompt_tone]
                else:
                    message = MessageSwitchDisplay(self._device_protocol_version)
            elif attr in [
                    DeviceAttributes.indirect_wind,
                    DeviceAttributes.breezeless
            ]:
                message = MessageNewProtocolSet(self._device_protocol_version)
                setattr(message, str(attr), value)
                message.prompt_tone = self._attributes[DeviceAttributes.prompt_tone]
            elif attr == DeviceAttributes.fresh_air_power:
                if self._fresh_air_version is not None:
                    message = MessageNewProtocolSet(self._device_protocol_version)
                    setattr(
                        message,
                        str(self._fresh_air_version),
                        [value, self._attributes[DeviceAttributes.fresh_air_fan_speed]]
                    )
            elif attr == DeviceAttributes.fresh_air_mode:
                if value in MideaACDevice._fresh_air_fan_speeds.values():
                    speed = list(MideaACDevice._fresh_air_fan_speeds.keys())[
                        list(MideaACDevice._fresh_air_fan_speeds.values()).index(value)
                    ]
                    fresh_air = [True, speed] if speed > 0 else \
                        [False, self._attributes[DeviceAttributes.fresh_air_fan_speed]]
                    message = MessageNewProtocolSet(self._device_protocol_version)
                    setattr(
                        message,
                        str(self._fresh_air_version),
                        fresh_air
                    )
                elif not value:
                    message = MessageNewProtocolSet(self._device_protocol_version)
                    setattr(
                        message,
                        str(self._fresh_air_version),
                        [False, self._attributes[DeviceAttributes.fresh_air_fan_speed]]
                    )
            elif attr == DeviceAttributes.fresh_air_fan_speed:
                if self._fresh_air_version is not None:
                    message = MessageNewProtocolSet(self._device_protocol_version)
                    fresh_air = [True, value] if value > 0 else \
                        [False, self._attributes[DeviceAttributes.fresh_air_fan_speed]]
                    setattr(
                        message,
                        str(self._fresh_air_version),
                        fresh_air
                    )
            elif attr in self._attributes.keys():
                message = self.make_message_uniq_set()
                if attr in [
                    DeviceAttributes.boost_mode,
                    DeviceAttributes.sleep_mode,
                    DeviceAttributes.frost_protect,
                    DeviceAttributes.comfort_mode,
                    DeviceAttributes.eco_mode
                ]:
                    message.boost_mode = False
                    message.sleep_mode = False
                    message.comfort_mode = False
                    message.eco_mode = False
                    message.frost_protect = False
                setattr(message, str(attr), value)
                if attr == DeviceAttributes.mode:
                    setattr(message, DeviceAttributes.power.value, True)
        if message is not None:
            self.build_send(message)

    def set_target_temperature(self, target_temperature, mode):
        message = self.make_message_uniq_set()
        message.target_temperature = target_temperature
        if mode is not None:
            message.power = True
            message.mode = mode
        self.build_send(message)

    def set_swing(self, swing_vertical, swing_horizontal):
        message = self.make_message_uniq_set()
        message.swing_vertical = swing_vertical
        message.swing_horizontal = swing_horizontal
        self.build_send(message)

    def set_customize(self, customize):
        self._temperature_step = self._default_temperature_step
        self._power_analysis_method = self._default_power_analysis_method
        if customize and len(customize) > 0:
            try:
                params = json.loads(customize)
                if params and "temperature_step" in params:
                    self._temperature_step = params.get("temperature_step")
                if params and "power_analysis_method" in params:
                    self._power_analysis_method = params.get("power_analysis_method")
            except Exception as e:
                _LOGGER.error(f"[{self.device_id}] Set customize error: {repr(e)}")
            self.update_all({"temperature_step": self._temperature_step})


class MideaAppliance(MideaACDevice):
    pass