"""Suppoort for Amcrest IP camera sensors."""
from datetime import timedelta
import logging

from amcrest import AmcrestError

from homeassistant.const import CONF_NAME, CONF_SENSORS
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity

from .const import (
    DATA_AMCREST, DEVICES, SENSOR_SCAN_INTERVAL_SECS, SERVICE_UPDATE)
from .helpers import log_update_error, service_signal

_LOGGER = logging.getLogger(__name__)

SCAN_INTERVAL = timedelta(seconds=SENSOR_SCAN_INTERVAL_SECS)

SENSOR_MOTION_DETECTOR = 'motion_detector'
SENSOR_PTZ_PRESET = 'ptz_preset'
SENSOR_SDCARD = 'sdcard'
# Sensor types are defined like: Name, units, icon
SENSORS = {
    SENSOR_MOTION_DETECTOR: ['Motion Detected', None, 'mdi:run'],
    SENSOR_PTZ_PRESET: ['PTZ Preset', None, 'mdi:camera-iris'],
    SENSOR_SDCARD: ['SD Used', '%', 'mdi:sd'],
}


async def async_setup_platform(
        hass, config, async_add_entities, discovery_info=None):
    """Set up a sensor for an Amcrest IP Camera."""
    if discovery_info is None:
        return

    name = discovery_info[CONF_NAME]
    device = hass.data[DATA_AMCREST][DEVICES][name]
    async_add_entities(
        [AmcrestSensor(name, device, sensor_type)
         for sensor_type in discovery_info[CONF_SENSORS]],
        True)


class AmcrestSensor(Entity):
    """A sensor implementation for Amcrest IP camera."""

    def __init__(self, name, device, sensor_type):
        """Initialize a sensor for Amcrest camera."""
        self._name = '{} {}'.format(name, SENSORS[sensor_type][0])
        self._signal_name = name
        self._api = device.api
        self._sensor_type = sensor_type
        self._state = None
        self._attrs = {}
        self._unit_of_measurement = SENSORS[sensor_type][1]
        self._icon = SENSORS[sensor_type][2]
        self._unsub_dispatcher = None

    @property
    def name(self):
        """Return the name of the sensor."""
        return self._name

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

    @property
    def device_state_attributes(self):
        """Return the state attributes."""
        return self._attrs

    @property
    def icon(self):
        """Icon to use in the frontend, if any."""
        return self._icon

    @property
    def unit_of_measurement(self):
        """Return the units of measurement."""
        return self._unit_of_measurement

    @property
    def available(self):
        """Return True if entity is available."""
        return self._api.available

    def update(self):
        """Get the latest data and updates the state."""
        if not self.available:
            return
        _LOGGER.debug("Updating %s sensor", self._name)

        try:
            if self._sensor_type == SENSOR_MOTION_DETECTOR:
                self._state = self._api.is_motion_detected
                self._attrs['Record Mode'] = self._api.record_mode

            elif self._sensor_type == SENSOR_PTZ_PRESET:
                self._state = self._api.ptz_presets_count

            elif self._sensor_type == SENSOR_SDCARD:
                storage = self._api.storage_all
                try:
                    self._attrs['Total'] = '{:.2f} {}'.format(
                        *storage['total'])
                except ValueError:
                    self._attrs['Total'] = '{} {}'.format(*storage['total'])
                try:
                    self._attrs['Used'] = '{:.2f} {}'.format(*storage['used'])
                except ValueError:
                    self._attrs['Used'] = '{} {}'.format(*storage['used'])
                try:
                    self._state = '{:.2f}'.format(storage['used_percent'])
                except ValueError:
                    self._state = storage['used_percent']
        except AmcrestError as error:
            log_update_error(_LOGGER, 'update', self.name, 'sensor', error)

    async def async_on_demand_update(self):
        """Update state."""
        self.async_schedule_update_ha_state(True)

    async def async_added_to_hass(self):
        """Subscribe to update signal."""
        self._unsub_dispatcher = async_dispatcher_connect(
            self.hass, service_signal(SERVICE_UPDATE, self._signal_name),
            self.async_on_demand_update)

    async def async_will_remove_from_hass(self):
        """Disconnect from update signal."""
        self._unsub_dispatcher()
