"""Collection of useful functions for the HomeKit component."""
import logging

import voluptuous as vol

from homeassistant.components import media_player
from homeassistant.core import split_entity_id
from homeassistant.const import (
    ATTR_CODE, ATTR_SUPPORTED_FEATURES, CONF_NAME, CONF_TYPE, TEMP_CELSIUS)
import homeassistant.helpers.config_validation as cv
import homeassistant.util.temperature as temp_util
from .const import (
    CONF_FEATURE, CONF_FEATURE_LIST, HOMEKIT_NOTIFY_ID, FEATURE_ON_OFF,
    FEATURE_PLAY_PAUSE, FEATURE_PLAY_STOP, FEATURE_TOGGLE_MUTE, TYPE_OUTLET,
    TYPE_SWITCH)

_LOGGER = logging.getLogger(__name__)


BASIC_INFO_SCHEMA = vol.Schema({
    vol.Optional(CONF_NAME): cv.string,
})

FEATURE_SCHEMA = BASIC_INFO_SCHEMA.extend({
    vol.Optional(CONF_FEATURE_LIST, default=None): cv.ensure_list,
})


CODE_SCHEMA = BASIC_INFO_SCHEMA.extend({
    vol.Optional(ATTR_CODE, default=None): vol.Any(None, cv.string),
})

MEDIA_PLAYER_SCHEMA = vol.Schema({
    vol.Required(CONF_FEATURE): vol.All(
        cv.string, vol.In((FEATURE_ON_OFF, FEATURE_PLAY_PAUSE,
                           FEATURE_PLAY_STOP, FEATURE_TOGGLE_MUTE))),
})

SWITCH_TYPE_SCHEMA = BASIC_INFO_SCHEMA.extend({
    vol.Optional(CONF_TYPE, default=TYPE_SWITCH): vol.All(
        cv.string, vol.In((TYPE_OUTLET, TYPE_SWITCH))),
})


def validate_entity_config(values):
    """Validate config entry for CONF_ENTITY."""
    entities = {}
    for entity_id, config in values.items():
        entity = cv.entity_id(entity_id)
        domain, _ = split_entity_id(entity)

        if not isinstance(config, dict):
            raise vol.Invalid('The configuration for {} must be '
                              ' a dictionary.'.format(entity))

        if domain in ('alarm_control_panel', 'lock'):
            config = CODE_SCHEMA(config)

        elif domain == media_player.DOMAIN:
            config = FEATURE_SCHEMA(config)
            feature_list = {}
            for feature in config[CONF_FEATURE_LIST]:
                params = MEDIA_PLAYER_SCHEMA(feature)
                key = params.pop(CONF_FEATURE)
                if key in feature_list:
                    raise vol.Invalid('A feature can be added only once for {}'
                                      .format(entity))
                feature_list[key] = params
            config[CONF_FEATURE_LIST] = feature_list

        elif domain == 'switch':
            config = SWITCH_TYPE_SCHEMA(config)

        else:
            config = BASIC_INFO_SCHEMA(config)

        entities[entity] = config
    return entities


def validate_media_player_features(state, feature_list):
    """Validate features for media players."""
    features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)

    supported_modes = []
    if features & (media_player.SUPPORT_TURN_ON |
                   media_player.SUPPORT_TURN_OFF):
        supported_modes.append(FEATURE_ON_OFF)
    if features & (media_player.SUPPORT_PLAY | media_player.SUPPORT_PAUSE):
        supported_modes.append(FEATURE_PLAY_PAUSE)
    if features & (media_player.SUPPORT_PLAY | media_player.SUPPORT_STOP):
        supported_modes.append(FEATURE_PLAY_STOP)
    if features & media_player.SUPPORT_VOLUME_MUTE:
        supported_modes.append(FEATURE_TOGGLE_MUTE)

    error_list = []
    for feature in feature_list:
        if feature not in supported_modes:
            error_list.append(feature)

    if error_list:
        _LOGGER.error("%s does not support features: %s",
                      state.entity_id, error_list)
        return False
    return True


def show_setup_message(hass, pincode):
    """Display persistent notification with setup information."""
    pin = pincode.decode()
    _LOGGER.info('Pincode: %s', pin)
    message = 'To setup Home Assistant in the Home App, enter the ' \
              'following code:\n### {}'.format(pin)
    hass.components.persistent_notification.create(
        message, 'HomeKit Setup', HOMEKIT_NOTIFY_ID)


def dismiss_setup_message(hass):
    """Dismiss persistent notification and remove QR code."""
    hass.components.persistent_notification.dismiss(HOMEKIT_NOTIFY_ID)


def convert_to_float(state):
    """Return float of state, catch errors."""
    try:
        return float(state)
    except (ValueError, TypeError):
        return None


def temperature_to_homekit(temperature, unit):
    """Convert temperature to Celsius for HomeKit."""
    return round(temp_util.convert(temperature, unit, TEMP_CELSIUS), 1)


def temperature_to_states(temperature, unit):
    """Convert temperature back from Celsius to Home Assistant unit."""
    return round(temp_util.convert(temperature, TEMP_CELSIUS, unit), 1)


def density_to_air_quality(density):
    """Map PM2.5 density to HomeKit AirQuality level."""
    if density <= 35:
        return 1
    if density <= 75:
        return 2
    if density <= 115:
        return 3
    if density <= 150:
        return 4
    return 5
