"""Config flow to configure Google Hangouts."""
import functools
import voluptuous as vol


from homeassistant import config_entries
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import callback

from .const import CONF_2FA, CONF_REFRESH_TOKEN, CONF_AUTH_CODE, \
    DOMAIN as HANGOUTS_DOMAIN


@callback
def configured_hangouts(hass):
    """Return the configures Google Hangouts Account."""
    entries = hass.config_entries.async_entries(HANGOUTS_DOMAIN)
    if entries:
        return entries[0]
    return None


@config_entries.HANDLERS.register(HANGOUTS_DOMAIN)
class HangoutsFlowHandler(config_entries.ConfigFlow):
    """Config flow Google Hangouts."""

    VERSION = 1
    CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH

    def __init__(self):
        """Initialize Google Hangouts config flow."""
        self._credentials = None
        self._refresh_token = None

    async def async_step_user(self, user_input=None):
        """Handle a flow start."""
        errors = {}

        if configured_hangouts(self.hass) is not None:
            return self.async_abort(reason="already_configured")

        if user_input is not None:
            from hangups import get_auth
            from .hangups_utils import (HangoutsCredentials,
                                        HangoutsRefreshToken,
                                        GoogleAuthError, Google2FAError)
            user_email = user_input[CONF_EMAIL]
            user_password = user_input[CONF_PASSWORD]
            user_auth_code = user_input.get(CONF_AUTH_CODE)
            manual_login = user_auth_code is not None

            user_pin = None
            self._credentials = HangoutsCredentials(user_email,
                                                    user_password,
                                                    user_pin,
                                                    user_auth_code)
            self._refresh_token = HangoutsRefreshToken(None)
            try:
                await self.hass.async_add_executor_job(
                    functools.partial(get_auth,
                                      self._credentials,
                                      self._refresh_token,
                                      manual_login=manual_login)
                )

                return await self.async_step_final()
            except GoogleAuthError as err:
                if isinstance(err, Google2FAError):
                    return await self.async_step_2fa()
                msg = str(err)
                if msg == 'Unknown verification code input':
                    errors['base'] = 'invalid_2fa_method'
                else:
                    errors['base'] = 'invalid_login'

        return self.async_show_form(
            step_id='user',
            data_schema=vol.Schema({
                vol.Required(CONF_EMAIL): str,
                vol.Required(CONF_PASSWORD): str,
                vol.Optional(CONF_AUTH_CODE): str
            }),
            errors=errors
        )

    async def async_step_2fa(self, user_input=None):
        """Handle the 2fa step, if needed."""
        errors = {}

        if user_input is not None:
            from hangups import get_auth
            from .hangups_utils import GoogleAuthError
            self._credentials.set_verification_code(user_input[CONF_2FA])
            try:
                await self.hass.async_add_executor_job(get_auth,
                                                       self._credentials,
                                                       self._refresh_token)

                return await self.async_step_final()
            except GoogleAuthError:
                errors['base'] = 'invalid_2fa'

        return self.async_show_form(
            step_id=CONF_2FA,
            data_schema=vol.Schema({
                vol.Required(CONF_2FA): str,
            }),
            errors=errors
        )

    async def async_step_final(self):
        """Handle the final step, create the config entry."""
        return self.async_create_entry(
            title=self._credentials.get_email(),
            data={
                CONF_EMAIL: self._credentials.get_email(),
                CONF_REFRESH_TOKEN: self._refresh_token.get()
            })

    async def async_step_import(self, _):
        """Handle a flow import."""
        return await self.async_step_user()
