# -*- coding: utf8 -*-
import asyncio
import logging
import uuid

import aiojobs.aiohttp
from homehub_backend.lib.services import BaseService, ServiceData
from homehub_tradfri.defs import kServiceTradfri
import pytradfri
import pytradfri.api.aiocoap_api

LOGGER = logging.getLogger('homehub.tradfri.services')


class TradfriService(BaseService):
    KIND = kServiceTradfri

    def __init__(self, app, instance, characteristics):
        super(TradfriService, self).__init__(app, instance, characteristics)
        self.api_factory = None
        self.gateway = None
        self.job = None
        self.started = False

    def state_key(self):
        state_key = super(TradfriService, self).state_key()
        return '{state_key}.{host}.{key}'.format(
            state_key=state_key,
            host=self.characteristics['host'],
            key=self.characteristics['key'],
        )

    async def current_data(self):
        result = ServiceData()

        try:
            result.data = {
                'groups': await self.get_groups(),
                'lights': await self.get_lights(),
            }
        except Exception as exc:
            LOGGER.error('Unhandled exception!', exc_info=exc)
            result.exception = exc

        return result

    async def call_api(self, commands):
        api = self.api_factory.request
        result = await api(commands)

        return result

    async def get_lights(self):
        lights_command = self.gateway.get_devices()
        lights_commands = await self.call_api(lights_command)

        result = await self.call_api(lights_commands)
        return [
            {
                'id': light.id,
                'name': light.name,
                'state': light.light_control.lights[0].state,
                'reachable': light.reachable,
                'dimmer': light.light_control.lights[0].dimmer,
            }
            for light in filter(lambda x: x.has_light_control, result)
        ]

    async def get_light(self, light_id):
        light_command = self.gateway.get_device(light_id)
        light = await self.call_api(light_command)

        return light

    async def set_light_state(self, light_id, next_state):
        light = await self.get_light(light_id)

        set_state_command = light.light_control.set_state(next_state, index=0)
        await self.call_api(set_state_command)

    async def get_groups(self):
        groups_command = self.gateway.get_groups()
        groups_commands = await self.call_api(groups_command)

        result = await self.call_api(groups_commands)
        return [
            {
                'id': group.id,
                'name': group.name,
                'member_ids': group.member_ids,
            }
            for group in result
        ]

    async def set_lights_state(self, light_ids, next_state):
        _ = await asyncio.gather(*[
            self.set_light_state(light_id, next_state)
            for light_id in light_ids
        ])

        lights = await self.get_lights()
        return list(filter(lambda light: light['id'] in light_ids, lights))

    async def worker(self):
        while True:
            await asyncio.sleep(60)
            await self.notify()

            if self.job.closed:
                break

    async def start(self):
        if not self.started:
            psk_id = None
            psk = None

            if self.state is not None:
                psk_id = self.state.get('psk_id')
                psk = self.state.get('psk')

            if not psk_id:
                psk_id = uuid.uuid4().hex

            LOGGER.debug('TradfriService.start() {psk_id} {has_psk} {characteristics}'.format(
                psk_id=psk_id,
                has_psk=(psk is not None),
                characteristics=self.characteristics,
            ))

            self.api_factory = await pytradfri.api.aiocoap_api.APIFactory.init(
                host=self.characteristics['host'],
                psk_id=psk_id,
                psk=psk,
            )

            if not psk:
                psk = await self.api_factory.generate_psk(
                    self.characteristics['key'],
                )

            self.gateway = pytradfri.Gateway()

            if not self.job:
                scheduler = aiojobs.aiohttp.get_scheduler_from_app(self.app)
                self.job = await scheduler.spawn(self.worker())

            self.set_state({
                'psk_id': psk_id,
                'psk': psk,
            })

            self.started = True

    async def stop(self):
        LOGGER.debug('TradfriService.stop()')
        if self.gateway:
            self.gateway = None

        if self.api_factory:
            self.api_factory = None

        if self.job is not None and not self.job.closed:
            await self.job.close()
