"""Hue sensor entities."""
from aiohue.sensors import (
    TYPE_ZLL_LIGHTLEVEL,
    TYPE_ZLL_ROTARY,
    TYPE_ZLL_SWITCH,
    TYPE_ZLL_TEMPERATURE,
)

from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity
from homeassistant.const import (
    DEVICE_CLASS_BATTERY,
    DEVICE_CLASS_ILLUMINANCE,
    DEVICE_CLASS_TEMPERATURE,
    LIGHT_LUX,
    PERCENTAGE,
    TEMP_CELSIUS,
)

from .const import DOMAIN as HUE_DOMAIN
from .sensor_base import SENSOR_CONFIG_MAP, GenericHueSensor, GenericZLLSensor

LIGHT_LEVEL_NAME_FORMAT = "{} light level"
REMOTE_NAME_FORMAT = "{} battery level"
TEMPERATURE_NAME_FORMAT = "{} temperature"


async def async_setup_entry(hass, config_entry, async_add_entities):
    """Defer sensor setup to the shared sensor module."""
    bridge = hass.data[HUE_DOMAIN][config_entry.entry_id]

    if not bridge.sensor_manager:
        return

    await bridge.sensor_manager.async_register_component("sensor", async_add_entities)


class GenericHueGaugeSensorEntity(GenericZLLSensor, SensorEntity):
    """Parent class for all 'gauge' Hue device sensors."""


class HueLightLevel(GenericHueGaugeSensorEntity):
    """The light level sensor entity for a Hue motion sensor device."""

    _attr_device_class = DEVICE_CLASS_ILLUMINANCE
    _attr_native_unit_of_measurement = LIGHT_LUX

    @property
    def native_value(self):
        """Return the state of the device."""
        if self.sensor.lightlevel is None:
            return None

        # https://developers.meethue.com/develop/hue-api/supported-devices/#clip_zll_lightlevel
        # Light level in 10000 log10 (lux) +1 measured by sensor. Logarithm
        # scale used because the human eye adjusts to light levels and small
        # changes at low lux levels are more noticeable than at high lux
        # levels.
        return round(float(10 ** ((self.sensor.lightlevel - 1) / 10000)), 2)

    @property
    def extra_state_attributes(self):
        """Return the device state attributes."""
        attributes = super().extra_state_attributes
        attributes.update(
            {
                "lightlevel": self.sensor.lightlevel,
                "daylight": self.sensor.daylight,
                "dark": self.sensor.dark,
                "threshold_dark": self.sensor.tholddark,
                "threshold_offset": self.sensor.tholdoffset,
            }
        )
        return attributes


class HueTemperature(GenericHueGaugeSensorEntity):
    """The temperature sensor entity for a Hue motion sensor device."""

    _attr_device_class = DEVICE_CLASS_TEMPERATURE
    _attr_state_class = STATE_CLASS_MEASUREMENT
    _attr_native_unit_of_measurement = TEMP_CELSIUS

    @property
    def native_value(self):
        """Return the state of the device."""
        if self.sensor.temperature is None:
            return None

        return self.sensor.temperature / 100


class HueBattery(GenericHueSensor, SensorEntity):
    """Battery class for when a batt-powered device is only represented as an event."""

    _attr_device_class = DEVICE_CLASS_BATTERY
    _attr_state_class = STATE_CLASS_MEASUREMENT
    _attr_native_unit_of_measurement = PERCENTAGE

    @property
    def unique_id(self):
        """Return a unique identifier for this device."""
        return f"{self.sensor.uniqueid}-battery"

    @property
    def native_value(self):
        """Return the state of the battery."""
        return self.sensor.battery


SENSOR_CONFIG_MAP.update(
    {
        TYPE_ZLL_LIGHTLEVEL: {
            "platform": "sensor",
            "name_format": LIGHT_LEVEL_NAME_FORMAT,
            "class": HueLightLevel,
        },
        TYPE_ZLL_TEMPERATURE: {
            "platform": "sensor",
            "name_format": TEMPERATURE_NAME_FORMAT,
            "class": HueTemperature,
        },
        TYPE_ZLL_SWITCH: {
            "platform": "sensor",
            "name_format": REMOTE_NAME_FORMAT,
            "class": HueBattery,
        },
        TYPE_ZLL_ROTARY: {
            "platform": "sensor",
            "name_format": REMOTE_NAME_FORMAT,
            "class": HueBattery,
        },
    }
)