"""Support for power sensors in WeMo Insight devices."""
import asyncio
from datetime import timedelta
from typing import Callable

from homeassistant.components.sensor import (
    STATE_CLASS_MEASUREMENT,
    STATE_CLASS_TOTAL_INCREASING,
    SensorEntity,
    SensorEntityDescription,
)
from homeassistant.const import (
    DEVICE_CLASS_ENERGY,
    DEVICE_CLASS_POWER,
    ENERGY_KILO_WATT_HOUR,
    POWER_WATT,
)
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.typing import StateType
from homeassistant.util import Throttle, convert

from .const import DOMAIN as WEMO_DOMAIN
from .entity import WemoSubscriptionEntity
from .wemo_device import DeviceWrapper

SCAN_INTERVAL = timedelta(seconds=10)


async def async_setup_entry(hass, config_entry, async_add_entities):
    """Set up WeMo sensors."""

    async def _discovered_wemo(device: DeviceWrapper):
        """Handle a discovered Wemo device."""

        @Throttle(SCAN_INTERVAL)
        def update_insight_params():
            device.wemo.update_insight_params()

        async_add_entities(
            [
                InsightCurrentPower(device, update_insight_params),
                InsightTodayEnergy(device, update_insight_params),
            ]
        )

    async_dispatcher_connect(hass, f"{WEMO_DOMAIN}.sensor", _discovered_wemo)

    await asyncio.gather(
        *(
            _discovered_wemo(device)
            for device in hass.data[WEMO_DOMAIN]["pending"].pop("sensor")
        )
    )


class InsightSensor(WemoSubscriptionEntity, SensorEntity):
    """Common base for WeMo Insight power sensors."""

    _name_suffix: str

    def __init__(self, device: DeviceWrapper, update_insight_params: Callable) -> None:
        """Initialize the WeMo Insight power sensor."""
        super().__init__(device)
        self._update_insight_params = update_insight_params

    @property
    def name(self) -> str:
        """Return the name of the entity if any."""
        return f"{super().name} {self.entity_description.name}"

    @property
    def unique_id(self) -> str:
        """Return the id of this entity."""
        return f"{super().unique_id}_{self.entity_description.key}"

    @property
    def available(self) -> str:
        """Return true if sensor is available."""
        return (
            self.entity_description.key in self.wemo.insight_params
            and super().available
        )

    def _update(self, force_update=True) -> None:
        with self._wemo_exception_handler("update status"):
            if force_update or not self.wemo.insight_params:
                self._update_insight_params()


class InsightCurrentPower(InsightSensor):
    """Current instantaineous power consumption."""

    entity_description = SensorEntityDescription(
        key="currentpower",
        name="Current Power",
        device_class=DEVICE_CLASS_POWER,
        state_class=STATE_CLASS_MEASUREMENT,
        native_unit_of_measurement=POWER_WATT,
    )

    @property
    def native_value(self) -> StateType:
        """Return the current power consumption."""
        return (
            convert(self.wemo.insight_params[self.entity_description.key], float, 0.0)
            / 1000.0
        )


class InsightTodayEnergy(InsightSensor):
    """Energy used today."""

    entity_description = SensorEntityDescription(
        key="todaymw",
        name="Today Energy",
        device_class=DEVICE_CLASS_ENERGY,
        state_class=STATE_CLASS_TOTAL_INCREASING,
        native_unit_of_measurement=ENERGY_KILO_WATT_HOUR,
    )

    @property
    def native_value(self) -> StateType:
        """Return the current energy use today."""
        miliwatts = convert(
            self.wemo.insight_params[self.entity_description.key], float, 0.0
        )
        return round(miliwatts / (1000.0 * 1000.0 * 60), 2)