"""Hue sensor resources."""
from __future__ import annotations

from .api import APIItems

TYPE_DAYLIGHT = "Daylight"

TYPE_CLIP_GENERICFLAG = "CLIPGenericFlag"
TYPE_CLIP_GENERICSTATUS = "CLIPGenericStatus"
TYPE_CLIP_HUMIDITY = "CLIPHumidity"
TYPE_CLIP_LIGHTLEVEL = "CLIPLightLevel"
TYPE_CLIP_OPENCLOSE = "CLIPOpenClose"
TYPE_CLIP_PRESENCE = "CLIPPresence"
TYPE_CLIP_SWITCH = "CLIPSwitch"
TYPE_CLIP_TEMPERATURE = "CLIPTemperature"

TYPE_GEOFENCE = "Geofence"

TYPE_ZGP_SWITCH = "ZGPSwitch"

TYPE_ZLL_LIGHTLEVEL = "ZLLLightLevel"
TYPE_ZLL_PRESENCE = "ZLLPresence"
TYPE_ZLL_ROTARY = "ZLLRelativeRotary"
TYPE_ZLL_SWITCH = "ZLLSwitch"
TYPE_ZLL_TEMPERATURE = "ZLLTemperature"

ZGP_SWITCH_BUTTON_1 = 34
ZGP_SWITCH_BUTTON_2 = 16
ZGP_SWITCH_BUTTON_3 = 17
ZGP_SWITCH_BUTTON_4 = 18

ZLL_SWITCH_BUTTON_1_INITIAL_PRESS = 1000
ZLL_SWITCH_BUTTON_2_INITIAL_PRESS = 2000
ZLL_SWITCH_BUTTON_3_INITIAL_PRESS = 3000
ZLL_SWITCH_BUTTON_4_INITIAL_PRESS = 4000

ZLL_SWITCH_BUTTON_1_HOLD = 1001
ZLL_SWITCH_BUTTON_2_HOLD = 2001
ZLL_SWITCH_BUTTON_3_HOLD = 3001
ZLL_SWITCH_BUTTON_4_HOLD = 4001

ZLL_SWITCH_BUTTON_1_SHORT_RELEASED = 1002
ZLL_SWITCH_BUTTON_2_SHORT_RELEASED = 2002
ZLL_SWITCH_BUTTON_3_SHORT_RELEASED = 3002
ZLL_SWITCH_BUTTON_4_SHORT_RELEASED = 4002

ZLL_SWITCH_BUTTON_1_LONG_RELEASED = 1003
ZLL_SWITCH_BUTTON_2_LONG_RELEASED = 2003
ZLL_SWITCH_BUTTON_3_LONG_RELEASED = 3003
ZLL_SWITCH_BUTTON_4_LONG_RELEASED = 4003

EVENT_BUTTON = "button"
EVENT_LIGHTLEVEL = "light_level"
EVENT_MOTION = "motion"
EVENT_POWER = "device_power"
EVENT_TEMPERATURE = "temperature"


class Sensors(APIItems):
    """Represents Hue Sensors.

    https://developers.meethue.com/documentation/sensors-api
    """

    def __init__(self, logger, raw, request):
        super().__init__(logger, raw, request, "sensors", create_sensor)


class GenericSensor:
    """Represents the base Hue sensor."""

    ITEM_TYPE = "sensors"

    def __init__(self, id, raw, request):
        self.id = id
        self.raw = raw
        self._request = request
        self.last_event = None

    @property
    def name(self):
        return self.raw["name"]

    @property
    def type(self):
        return self.raw["type"]

    @property
    def modelid(self):
        return self.raw["modelid"]

    @property
    def manufacturername(self):
        return self.raw["manufacturername"]

    @property
    def productname(self):
        return self.raw.get("productname")

    @property
    def uniqueid(self):
        return self.raw.get("uniqueid")

    @property
    def swversion(self):
        return self.raw.get("swversion")

    @property
    def state(self):
        return self.raw["state"]

    @property
    def config(self):
        return self.raw["config"]


class GenericCLIPSensor(GenericSensor):
    @property
    def battery(self):
        return self.raw["state"].get("battery")

    @property
    def lastupdated(self):
        return self.raw["state"]["lastupdated"]

    @property
    def on(self):
        return self.raw["config"]["on"]

    @property
    def reachable(self):
        return self.raw["config"]["reachable"]

    @property
    def url(self):
        return self.raw["config"].get("url")

    async def set_config(self, config):
        """Change config of a CLIP sensor."""
        await self._request("put", f"sensors/{self.id}/config", json=config)

    async def set_state(self, state):
        """Change state of a CLIP sensor."""
        await self._request("put", f"sensors/{self.id}/state", json=state)


class GenericZLLSensor(GenericSensor):
    @property
    def battery(self):
        return self.raw["state"].get("battery", self.raw["config"].get("battery"))

    @property
    def lastupdated(self):
        return self.raw["state"].get("lastupdated")

    @property
    def on(self):
        return self.raw["config"]["on"]

    @property
    def reachable(self):
        return self.raw["config"]["reachable"]


class GenericSwitchSensor:
    @property
    def buttonevent(self):
        return self.raw["state"]["buttonevent"]

    @property
    def inputs(self):
        return self.raw.get("capabilities", {}).get("inputs")

    async def set_config(self, on=None):
        """Change config of a Switch sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


class DaylightSensor(GenericSensor):
    @property
    def configured(self):
        return self.raw["config"]["configured"]

    @property
    def daylight(self):
        return self.raw["state"]["daylight"]

    @property
    def on(self):
        return self.raw["config"]["on"]

    @property
    def sunriseoffset(self):
        return self.raw["config"]["sunriseoffset"]

    @property
    def sunsetoffset(self):
        return self.raw["config"]["sunsetoffset"]

    async def set_config(self, on=None, long=None, lat=None, sunriseoffset=None, sunsetoffset=None):
        """Change config of a Daylight sensor."""
        data = {
            key: value
            for key, value in {
                "on": on,
                "long": long,
                "lat": lat,
                "sunriseoffset": sunriseoffset,
                "sunsetoffset": sunsetoffset,
            }.items()
            if value is not None
        }

        await self._request("put", f"sensors/{self.id}/config", json=data)


class GeofenceSensor(GenericSensor):
    @property
    def on(self):
        return self.raw["config"]["on"]

    @property
    def presence(self):
        return self.raw["state"]["presence"]

    @property
    def reachable(self):
        return self.raw["config"]["reachable"]

    async def set_config(self, on=None):
        """Change config of the Geofence sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


class CLIPPresenceSensor(GenericCLIPSensor):
    @property
    def presence(self):
        return self.raw["state"]["presence"]

    async def set_config(self, on=None):
        """Change config of a CLIP Presence sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


class ZLLPresenceSensor(GenericZLLSensor):
    @property
    def presence(self):
        return self.raw["state"]["presence"]

    async def set_config(self, on=None, sensitivity=None, sensitivitymax=None):
        """Change config of a ZLL Presence sensor."""
        data = {
            key: value
            for key, value in {
                "on": on,
                "sensitivity": sensitivity,
                "sensitivitymax": sensitivitymax,
            }.items()
            if value is not None
        }

        await self._request("put", f"sensors/{self.id}/config", json=data)


class ZLLRotarySensor(GenericZLLSensor):
    @property
    def rotaryevent(self):
        return self.raw["state"]["rotaryevent"]

    @property
    def expectedrotation(self):
        return self.raw["state"]["expectedrotation"]

    @property
    def expectedeventduration(self):
        return self.raw["state"]["expectedeventduration"]

    async def set_config(self, on=None):
        """Change config of a ZLL Rotary sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


class CLIPSwitchSensor(GenericCLIPSensor):
    @property
    def buttonevent(self):
        return self.raw["state"]["buttonevent"]

    async def set_config(self, on=None):
        """Change config of a CLIP Switch sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


class ZGPSwitchSensor(GenericSensor, GenericSwitchSensor):
    @property
    def lastupdated(self):
        return self.raw["state"].get("lastupdated")

    @property
    def on(self):
        return self.raw["config"]["on"]


class ZLLSwitchSensor(GenericZLLSensor, GenericSwitchSensor):
    pass


class CLIPLightLevelSensor(GenericCLIPSensor):
    @property
    def dark(self):
        return self.raw["state"]["dark"]

    @property
    def daylight(self):
        return self.raw["state"]["daylight"]

    @property
    def lightlevel(self):
        return self.raw["state"]["lightlevel"]

    @property
    def tholddark(self):
        return self.raw["config"]["tholddark"]

    @property
    def tholdoffset(self):
        return self.raw["config"]["tholdoffset"]

    async def set_config(self, on=None, tholddark=None, tholdoffset=None):
        """Change config of a CLIP LightLevel sensor."""
        data = {
            key: value
            for key, value in {
                "on": on,
                "tholddark": tholddark,
                "tholdoffset": tholdoffset,
            }.items()
            if value is not None
        }

        await self._request("put", f"sensors/{self.id}/config", json=data)


class ZLLLightLevelSensor(GenericZLLSensor):
    @property
    def dark(self):
        return self.raw["state"]["dark"]

    @property
    def daylight(self):
        return self.raw["state"]["daylight"]

    @property
    def lightlevel(self):
        return self.raw["state"]["lightlevel"]

    @property
    def tholddark(self):
        return self.raw["config"]["tholddark"]

    @property
    def tholdoffset(self):
        return self.raw["config"]["tholdoffset"]

    async def set_config(self, on=None, tholddark=None, tholdoffset=None):
        """Change config of a ZLL LightLevel sensor."""
        data = {
            key: value
            for key, value in {
                "on": on,
                "tholddark": tholddark,
                "tholdoffset": tholdoffset,
            }.items()
            if value is not None
        }

        await self._request("put", f"sensors/{self.id}/config", json=data)


class CLIPTemperatureSensor(GenericCLIPSensor):
    @property
    def temperature(self):
        return self.raw["state"]["temperature"]

    async def set_config(self, on=None):
        """Change config of a CLIP Temperature sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


class ZLLTemperatureSensor(GenericZLLSensor):
    @property
    def temperature(self):
        return self.raw["state"]["temperature"]

    async def set_config(self, on=None):
        """Change config of a ZLL Temperature sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


class CLIPGenericFlagSensor(GenericCLIPSensor):
    @property
    def flag(self):
        return self.raw["state"]["flag"]

    async def set_config(self, on=None):
        """Change config of a CLIP Generic Flag sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


class CLIPGenericStatusSensor(GenericCLIPSensor):
    @property
    def status(self):
        return self.raw["state"]["status"]

    async def set_config(self, on=None):
        """Change config of a CLIP Generic Status sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


class CLIPHumiditySensor(GenericCLIPSensor):
    @property
    def humidity(self):
        return self.raw["state"]["humidity"]

    async def set_config(self, on=None):
        """Change config of a CLIP Humidity sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


class CLIPOpenCloseSensor(GenericCLIPSensor):
    @property
    def open(self):
        return self.raw["state"]["open"]

    async def set_config(self, on=None):
        """Change config of a CLIP Open Close sensor."""
        data = {} if on is None else {"on": on}

        await self._request("put", f"sensors/{self.id}/config", json=data)


def create_sensor(id, raw, request):
    type = raw["type"]

    if type == TYPE_DAYLIGHT:
        return DaylightSensor(id, raw, request)

    elif type == TYPE_CLIP_GENERICFLAG:
        return CLIPGenericFlagSensor(id, raw, request)
    elif type == TYPE_CLIP_GENERICSTATUS:
        return CLIPGenericStatusSensor(id, raw, request)
    elif type == TYPE_CLIP_HUMIDITY:
        return CLIPHumiditySensor(id, raw, request)
    elif type == TYPE_CLIP_LIGHTLEVEL:
        return CLIPLightLevelSensor(id, raw, request)
    elif type == TYPE_CLIP_OPENCLOSE:
        return CLIPOpenCloseSensor(id, raw, request)
    elif type == TYPE_CLIP_PRESENCE:
        return CLIPPresenceSensor(id, raw, request)
    elif type == TYPE_CLIP_SWITCH:
        return CLIPSwitchSensor(id, raw, request)
    elif type == TYPE_CLIP_TEMPERATURE:
        return CLIPTemperatureSensor(id, raw, request)

    elif type == TYPE_GEOFENCE:
        return GeofenceSensor(id, raw, request)

    elif type == TYPE_ZGP_SWITCH:
        return ZGPSwitchSensor(id, raw, request)

    elif type == TYPE_ZLL_LIGHTLEVEL:
        return ZLLLightLevelSensor(id, raw, request)
    elif type == TYPE_ZLL_PRESENCE:
        return ZLLPresenceSensor(id, raw, request)
    elif type == TYPE_ZLL_ROTARY:
        return ZLLRotarySensor(id, raw, request)
    elif type == TYPE_ZLL_SWITCH:
        return ZLLSwitchSensor(id, raw, request)
    elif type == TYPE_ZLL_TEMPERATURE:
        return ZLLTemperatureSensor(id, raw, request)

    else:
        return GenericSensor(id, raw, request)
