"""
Component to create an interface to a Pilight daemon (https://pilight.org/).

For more details about this component, please refer to the documentation at
https://home-assistant.io/components/pilight/
"""
# pylint: disable=import-error
import logging
import socket

import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import ensure_list
from homeassistant.const import EVENT_HOMEASSISTANT_START
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.const import CONF_HOST, CONF_PORT

REQUIREMENTS = ['pilight==0.0.2']

DOMAIN = "pilight"
EVENT = 'pilight_received'
SERVICE_NAME = 'send'

CONF_WHITELIST = 'whitelist'

CONFIG_SCHEMA = vol.Schema({
    DOMAIN: vol.Schema({
        vol.Required(CONF_HOST, default='127.0.0.1'): cv.string,
        vol.Required(CONF_PORT, default=5000): vol.Coerce(int),
        vol.Optional(CONF_WHITELIST): {cv.string: [cv.string]}
    }),
}, extra=vol.ALLOW_EXTRA)

# The pilight code schema depends on the protocol
# Thus only require to have the protocol information
ATTR_PROTOCOL = 'protocol'
RF_CODE_SCHEMA = vol.Schema({vol.Required(ATTR_PROTOCOL): cv.string},
                            extra=vol.ALLOW_EXTRA)

_LOGGER = logging.getLogger(__name__)


def setup(hass, config):
    """Setup the pilight component."""
    from pilight import pilight

    try:
        pilight_client = pilight.Client(host=config[DOMAIN][CONF_HOST],
                                        port=config[DOMAIN][CONF_PORT])
    except (socket.error, socket.timeout) as err:
        _LOGGER.error(
            "Unable to connect to %s on port %s: %s",
            config[CONF_HOST], config[CONF_PORT], err)
        return False

    # Start / stop pilight-daemon connection with HA start/stop
    def start_pilight_client(_):
        """Called once when home assistant starts."""
        pilight_client.start()

    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_pilight_client)

    def stop_pilight_client(_):
        """Called once when home assistant stops."""
        pilight_client.stop()

    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_pilight_client)

    def send_code(call):
        """Send RF code to the pilight-daemon."""
        message_data = call.data

        # Patch data because of bug:
        # https://github.com/pilight/pilight/issues/296
        # Protocol has to be in a list otherwise segfault in pilight-daemon
        message_data["protocol"] = ensure_list(message_data["protocol"])

        try:
            pilight_client.send_code(message_data)
        except IOError:
            _LOGGER.error('Pilight send failed for %s', str(message_data))

    hass.services.register(DOMAIN, SERVICE_NAME,
                           send_code, schema=RF_CODE_SCHEMA)

    # Publish received codes on the HA event bus
    # A whitelist of codes to be published in the event bus
    whitelist = config[DOMAIN].get('whitelist', False)

    def handle_received_code(data):
        """Called when RF codes are received."""
        # Unravel dict of dicts to make event_data cut in automation rule
        # possible
        data = dict(
            {'protocol': data['protocol'],
             'uuid': data['uuid']},
            **data['message'])

        # No whitelist defined, put data on event bus
        if not whitelist:
            hass.bus.fire(EVENT, data)
        # Check if data matches the defined whitelist
        elif all(data[key] in whitelist[key] for key in whitelist):
            hass.bus.fire(EVENT, data)

    pilight_client.set_callback(handle_received_code)

    return True
