"""Support for lights from FHEM"""

import voluptuous as vol
import logging

from homeassistant.components.light import ATTR_BRIGHTNESS, PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, Light, ATTR_TRANSITION
from homeassistant.const import CONF_NAME
import homeassistant.helpers.config_validation as cv
from . import DATA_FHEM, device_error_reporting, CONF_FHEM_IDS

CONF_DIMMER = 'dimmer'


_LOGGER = logging.getLogger(__name__)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_FHEM_IDS): vol.All(cv.ensure_list, [cv.string]),
    vol.Optional(CONF_DIMMER, default=False): cv.boolean,
    vol.Required(CONF_NAME): cv.string,
})


async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
    """Set up lights for KNX platform."""
    connection = hass.data[DATA_FHEM]
    light = FhemLight(connection, config[CONF_NAME], config[CONF_FHEM_IDS], dimmer=config[CONF_DIMMER])
    for dev_id in config[CONF_FHEM_IDS]:
        connection.register_device(dev_id, light)
    async_add_entities([light])


class FhemLight(Light):

    def __init__(self, connection, name, ids, dimmer=False):
        self._brightness = None
        self.connection = connection
        self._dimmer = dimmer
        self._ids = ids
        self._name = name
        self._available = True

    @property
    def name(self):
        return self._name

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def available(self) -> bool:
        return self._available and self.connection.connected

    @property
    def supported_features(self):
        """Flag supported features."""
        flags = 0
        if self._dimmer:
            flags |= SUPPORT_BRIGHTNESS
        return flags

    @property
    def brightness(self):
        return self._brightness

    @property
    def is_on(self):
        """Return true if light is on."""
        if self._brightness is not None:
            return self._brightness > 0
        else:
            return None

    async def async_turn_on(self, **kwargs):
        brightness = kwargs.get(ATTR_BRIGHTNESS, self.brightness)
        transition_time = kwargs.get(ATTR_TRANSITION, None)

        if brightness is None:
            brightness = 255

        if self._dimmer:
            if transition_time is not None:
                # zero in the middle is the time until light is switched off,
                # which is disabled here when passing 0
                self.connection.fhem_set(self._ids[0], brightness / 255 * 100, 0, transition_time)
            else:
                self.connection.fhem_set(self._ids[0], brightness / 255 * 100)
        else:
            self.connection.fhem_set(self._ids[0], 'on')
        self._brightness = brightness

    async def async_turn_off(self, **kwargs):
        self.connection.fhem_set(self._ids[0], 'off')

    async def line_received(self, line):
        if line.startswith('dim:'):
            self._available = True
            _, new_dim_state, new_level = line.split(':')
            new_level = new_level.strip().lower()
            new_dim_state = new_dim_state.strip().lower()
            assert new_dim_state == 'stop' or new_dim_state == 'up' or new_dim_state == 'down'
            if new_dim_state == 'stop':
                if new_level == 'on':
                    self._brightness = 255
                elif new_level == 'off':
                    self._brightness = 0
                else:
                    new_level = int(float(new_level))  # first convert from string to floating point then truncate
                    assert 0 <= new_level <= 100
                    self._brightness = int(new_level / 100 * 255)
                await self.async_update_ha_state()
        elif line.startswith('level:') and not self._dimmer:
            self._available = True
            _, new_level = line.split(':')
            new_level = new_level.strip().lower()
            if new_level == 'on':
                self._brightness = 255
            elif new_level == 'off':
                self._brightness = 0
            else:
                try:
                    new_level = int(float(new_level))  # first convert from string to floating point then truncate
                    assert 0 <= new_level <= 100
                    self._brightness = int(new_level / 100 * 255)
                except ValueError:
                    pass
            await self.async_update_ha_state()
        elif line.startswith('ResndFail') or line.startswith('MISSING ACK'):
            self._available = False
            await self.async_update_ha_state()
        else:
            device_error_reporting(self.hass, line, component_type="Light", component_name=self.entity_id)
