"""Offer API to configure Home Assistant auth."""
import voluptuous as vol

from homeassistant.components import websocket_api


WS_TYPE_LIST = 'config/auth/list'
SCHEMA_WS_LIST = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
    vol.Required('type'): WS_TYPE_LIST,
})

WS_TYPE_DELETE = 'config/auth/delete'
SCHEMA_WS_DELETE = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
    vol.Required('type'): WS_TYPE_DELETE,
    vol.Required('user_id'): str,
})

WS_TYPE_CREATE = 'config/auth/create'
SCHEMA_WS_CREATE = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
    vol.Required('type'): WS_TYPE_CREATE,
    vol.Required('name'): str,
})


async def async_setup(hass):
    """Enable the Home Assistant views."""
    hass.components.websocket_api.async_register_command(
        WS_TYPE_LIST, websocket_list,
        SCHEMA_WS_LIST
    )
    hass.components.websocket_api.async_register_command(
        WS_TYPE_DELETE, websocket_delete,
        SCHEMA_WS_DELETE
    )
    hass.components.websocket_api.async_register_command(
        WS_TYPE_CREATE, websocket_create,
        SCHEMA_WS_CREATE
    )
    hass.components.websocket_api.async_register_command(websocket_update)
    return True


@websocket_api.require_admin
@websocket_api.async_response
async def websocket_list(hass, connection, msg):
    """Return a list of users."""
    result = [_user_info(u) for u in await hass.auth.async_get_users()]

    connection.send_message(
        websocket_api.result_message(msg['id'], result))


@websocket_api.require_admin
@websocket_api.async_response
async def websocket_delete(hass, connection, msg):
    """Delete a user."""
    if msg['user_id'] == connection.user.id:
        connection.send_message(websocket_api.error_message(
            msg['id'], 'no_delete_self',
            'Unable to delete your own account'))
        return

    user = await hass.auth.async_get_user(msg['user_id'])

    if not user:
        connection.send_message(websocket_api.error_message(
            msg['id'], 'not_found', 'User not found'))
        return

    await hass.auth.async_remove_user(user)

    connection.send_message(
        websocket_api.result_message(msg['id']))


@websocket_api.require_admin
@websocket_api.async_response
async def websocket_create(hass, connection, msg):
    """Create a user."""
    user = await hass.auth.async_create_user(msg['name'])

    connection.send_message(
        websocket_api.result_message(msg['id'], {
            'user': _user_info(user)
        }))


@websocket_api.require_admin
@websocket_api.async_response
@websocket_api.websocket_command({
    vol.Required('type'): 'config/auth/update',
    vol.Required('user_id'): str,
    vol.Optional('name'): str,
    vol.Optional('group_ids'): [str]
})
async def websocket_update(hass, connection, msg):
    """Update a user."""
    user = await hass.auth.async_get_user(msg.pop('user_id'))

    if not user:
        connection.send_message(websocket_api.error_message(
            msg['id'], websocket_api.const.ERR_NOT_FOUND, 'User not found'))
        return

    if user.system_generated:
        connection.send_message(websocket_api.error_message(
            msg['id'], 'cannot_modify_system_generated',
            'Unable to update system generated users.'))
        return

    msg.pop('type')
    msg_id = msg.pop('id')

    await hass.auth.async_update_user(user, **msg)

    connection.send_message(
        websocket_api.result_message(msg_id, {
            'user': _user_info(user),
        }))


def _user_info(user):
    """Format a user."""
    return {
        'id': user.id,
        'name': user.name,
        'is_owner': user.is_owner,
        'is_active': user.is_active,
        'system_generated': user.system_generated,
        'group_ids': [group.id for group in user.groups],
        'credentials': [
            {
                'type': c.auth_provider_type,
            } for c in user.credentials
        ]
    }