import time

import numpy as np

from kamzik3.constants import *
from kamzik3.devices.attribute import Attribute
from kamzik3.devices.device import Device
from kamzik3.snippets.snippetsDecorators import expose_method


class DeviceLight(Device):

    def __init__(self, device_id=None, config=None):
        super(DeviceLight, self).__init__(device_id, config)
        self.connect()

    def _init_attributes(self):
        super()._init_attributes()
        self.create_attribute(ATTR_INTENSITY, readonly=False, default_type=np.float16, min_value=0, max_value=100,
                              unit="%", decimals=1, set_function=self.set_intensity, set_value_when_set_function=False)
        self.create_attribute(ATTR_SETPOINT, default_value=75, readonly=False, default_type=np.float16, min_value=0,
                              max_value=100, unit="%", decimals=1)

    def handle_configuration(self):
        start_at = time.time()

        def _finish_configuration(*_, **__):
            self._config_commands()
            self._config_attributes()
            self.set_status(STATUS_CONFIGURED)
            self.logger.info(u"Device configuration took {} sec.".format(time.time() - start_at))

        _finish_configuration()

    def set_intensity(self, value, callback=None):
        raise NotImplementedError()

    @expose_method()
    def turn_on(self, callback=None):
        self.logger.info(u"Turn On")
        self.set_intensity(self.get_value(ATTR_SETPOINT))

    @expose_method()
    def turn_off(self, callback=None):
        self.logger.info(u"Turn Off")
        self.set_intensity(0)

    @expose_method()
    def stop(self):
        self.logger.info(u"Stop device")
        self.turn_off()

class DeviceLightAttribute(DeviceLight):

    def __init__(self, device, attribute, output_switch_attribute=None, device_id=None, config=None):
        self.device = device
        self.attribute = Attribute.list_attribute(attribute)
        self.output_switch_attribute = output_switch_attribute
        if output_switch_attribute is not None:
            self.output_switch_attribute = Attribute.list_attribute(output_switch_attribute)
        super().__init__(device_id, config)

    def connect(self, *args):
        super(DeviceLightAttribute, self).connect(*args)
        self.device.attach_attribute_callback(self.attribute, self.value_changed, key_filter=VALUE)
        self.device.attach_attribute_callback(ATTR_STATUS, self.set_status, key_filter=VALUE)

    def _init_attributes(self):
        DeviceLight._init_attributes(self)
        if self.output_switch_attribute is not None:
            self.add_attribute(ATTR_OUTPUT_SWITCH, self.device.get_attribute(self.output_switch_attribute))

    def value_changed(self, value):
        if value is None:
            return
        value_min, value_max = self.device.get_attribute(self.attribute + [MIN]), self.device.get_attribute(
            self.attribute + [MAX])
        intensity = ((value - value_min) * 100) / (value_max - value_min)
        self.set_raw_value(ATTR_INTENSITY, intensity)

    def set_intensity(self, value, callback=None):
        self.logger.info(u"Set light intensity to {} %".format(value))
        if value > 0:
            self.set_value(ATTR_SETPOINT, value)
        value_min, value_max = self.device.get_attribute(self.attribute + [MIN]), self.device.get_attribute(
            self.attribute + [MAX])
        attribute_value = ((value * (value_max - value_min) / 100) + value_min)
        self.device.set_attribute(self.attribute + [VALUE], attribute_value)

    @expose_method()
    def stop(self):
        self.device.stop()

    def close(self):
        self.device.detach_attribute_callback(self.attribute, self.value_changed)
        self.device.detach_attribute_callback(ATTR_STATUS, self.set_status)
        return super(DeviceLightAttribute, self).close()

    @expose_method()
    def turn_on(self, callback=None):
        self.logger.info(u"Turn On")
        if self.output_switch_attribute is not None:
            self.device.set_value(self.output_switch_attribute, True)
        self.set_intensity(self.get_value(ATTR_SETPOINT))

    @expose_method()
    def turn_off(self, callback=None):
        self.logger.info(u"Turn Off")
        if self.output_switch_attribute is not None:
            self.device.set_value(self.output_switch_attribute, False)
        self.set_intensity(self.get_value(ATTR_SETPOINT))