"""Support for Hangouts."""
import logging

from hangups.auth import GoogleAuthError
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.components.conversation.util import create_matcher
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant
from homeassistant.helpers import dispatcher, intent
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType

# We need an import from .config_flow, without it .config_flow is never loaded.
from .config_flow import HangoutsFlowHandler  # noqa: F401
from .const import (
    CONF_BOT,
    CONF_DEFAULT_CONVERSATIONS,
    CONF_ERROR_SUPPRESSED_CONVERSATIONS,
    CONF_INTENTS,
    CONF_MATCHERS,
    CONF_REFRESH_TOKEN,
    CONF_SENTENCES,
    DOMAIN,
    EVENT_HANGOUTS_CONNECTED,
    EVENT_HANGOUTS_CONVERSATIONS_CHANGED,
    EVENT_HANGOUTS_CONVERSATIONS_RESOLVED,
    INTENT_HELP,
    INTENT_SCHEMA,
    MESSAGE_SCHEMA,
    SERVICE_RECONNECT,
    SERVICE_SEND_MESSAGE,
    SERVICE_UPDATE,
    TARGETS_SCHEMA,
)
from .hangouts_bot import HangoutsBot
from .intents import HelpIntent

_LOGGER = logging.getLogger(__name__)

CONFIG_SCHEMA = vol.Schema(
    {
        DOMAIN: vol.Schema(
            {
                vol.Optional(CONF_INTENTS, default={}): vol.Schema(
                    {cv.string: INTENT_SCHEMA}
                ),
                vol.Optional(CONF_DEFAULT_CONVERSATIONS, default=[]): [TARGETS_SCHEMA],
                vol.Optional(CONF_ERROR_SUPPRESSED_CONVERSATIONS, default=[]): [
                    TARGETS_SCHEMA
                ],
            }
        )
    },
    extra=vol.ALLOW_EXTRA,
)


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    """Set up the Hangouts bot component."""
    if (conf := config.get(DOMAIN)) is None:
        hass.data[DOMAIN] = {
            CONF_INTENTS: {},
            CONF_DEFAULT_CONVERSATIONS: [],
            CONF_ERROR_SUPPRESSED_CONVERSATIONS: [],
        }
        return True

    hass.data[DOMAIN] = {
        CONF_INTENTS: conf[CONF_INTENTS],
        CONF_DEFAULT_CONVERSATIONS: conf[CONF_DEFAULT_CONVERSATIONS],
        CONF_ERROR_SUPPRESSED_CONVERSATIONS: conf[CONF_ERROR_SUPPRESSED_CONVERSATIONS],
    }

    if (
        hass.data[DOMAIN][CONF_INTENTS]
        and INTENT_HELP not in hass.data[DOMAIN][CONF_INTENTS]
    ):
        hass.data[DOMAIN][CONF_INTENTS][INTENT_HELP] = {CONF_SENTENCES: ["HELP"]}

    for data in hass.data[DOMAIN][CONF_INTENTS].values():
        matchers = []
        for sentence in data[CONF_SENTENCES]:
            matchers.append(create_matcher(sentence))

        data[CONF_MATCHERS] = matchers

    hass.async_create_task(
        hass.config_entries.flow.async_init(
            DOMAIN, context={"source": config_entries.SOURCE_IMPORT}
        )
    )

    return True


async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry) -> bool:
    """Set up a config entry."""
    try:
        bot = HangoutsBot(
            hass,
            config.data.get(CONF_REFRESH_TOKEN),
            hass.data[DOMAIN][CONF_INTENTS],
            hass.data[DOMAIN][CONF_DEFAULT_CONVERSATIONS],
            hass.data[DOMAIN][CONF_ERROR_SUPPRESSED_CONVERSATIONS],
        )
        hass.data[DOMAIN][CONF_BOT] = bot
    except GoogleAuthError as exception:
        _LOGGER.error("Hangouts failed to log in: %s", str(exception))
        return False

    dispatcher.async_dispatcher_connect(
        hass, EVENT_HANGOUTS_CONNECTED, bot.async_handle_update_users_and_conversations
    )

    dispatcher.async_dispatcher_connect(
        hass, EVENT_HANGOUTS_CONVERSATIONS_CHANGED, bot.async_resolve_conversations
    )

    dispatcher.async_dispatcher_connect(
        hass,
        EVENT_HANGOUTS_CONVERSATIONS_RESOLVED,
        bot.async_update_conversation_commands,
    )

    config.async_on_unload(
        hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, bot.async_handle_hass_stop)
    )

    await bot.async_connect()

    hass.services.async_register(
        DOMAIN,
        SERVICE_SEND_MESSAGE,
        bot.async_handle_send_message,
        schema=MESSAGE_SCHEMA,
    )
    hass.services.async_register(
        DOMAIN,
        SERVICE_UPDATE,
        bot.async_handle_update_users_and_conversations,
        schema=vol.Schema({}),
    )

    hass.services.async_register(
        DOMAIN, SERVICE_RECONNECT, bot.async_handle_reconnect, schema=vol.Schema({})
    )

    intent.async_register(hass, HelpIntent(hass))

    return True


async def async_unload_entry(hass: HomeAssistant, _: ConfigEntry) -> bool:
    """Unload a config entry."""
    bot = hass.data[DOMAIN].pop(CONF_BOT)
    await bot.async_disconnect()
    return True
