"""Config flow for Lutron Caseta."""
import logging

from pylutron_caseta.smartbridge import Smartbridge

from homeassistant import config_entries
from homeassistant.const import CONF_HOST

from . import DOMAIN  # pylint: disable=unused-import
from .const import (
    ABORT_REASON_ALREADY_CONFIGURED,
    ABORT_REASON_CANNOT_CONNECT,
    CONF_CA_CERTS,
    CONF_CERTFILE,
    CONF_KEYFILE,
    ERROR_CANNOT_CONNECT,
    STEP_IMPORT_FAILED,
)

_LOGGER = logging.getLogger(__name__)

ENTRY_DEFAULT_TITLE = "Caséta bridge"


class LutronCasetaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
    """Handle Lutron Caseta config flow."""

    VERSION = 1
    CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL

    def __init__(self):
        """Initialize a Lutron Caseta flow."""
        self.data = {}

    async def async_step_import(self, import_info):
        """Import a new Caseta bridge as a config entry.

        This flow is triggered by `async_setup`.
        """

        # Abort if existing entry with matching host exists.
        host = import_info[CONF_HOST]
        if any(
            host == entry.data[CONF_HOST] for entry in self._async_current_entries()
        ):
            return self.async_abort(reason=ABORT_REASON_ALREADY_CONFIGURED)

        # Store the imported config for other steps in this flow to access.
        self.data[CONF_HOST] = host
        self.data[CONF_KEYFILE] = import_info[CONF_KEYFILE]
        self.data[CONF_CERTFILE] = import_info[CONF_CERTFILE]
        self.data[CONF_CA_CERTS] = import_info[CONF_CA_CERTS]

        if not await self.async_validate_connectable_bridge_config():
            # Ultimately we won't have a dedicated step for import failure, but
            # in order to keep configuration.yaml-based configs transparently
            # working without requiring further actions from the user, we don't
            # display a form at all before creating a config entry in the
            # default case, so we're only going to show a form in case the
            # import fails.
            # This will change in an upcoming release where UI-based config flow
            # will become the default for the Lutron Caseta integration (which
            # will require users to go through a confirmation flow for imports).
            return await self.async_step_import_failed()

        return self.async_create_entry(title=ENTRY_DEFAULT_TITLE, data=self.data)

    async def async_step_import_failed(self, user_input=None):
        """Make failed import surfaced to user."""

        if user_input is None:
            return self.async_show_form(
                step_id=STEP_IMPORT_FAILED,
                description_placeholders={"host": self.data[CONF_HOST]},
                errors={"base": ERROR_CANNOT_CONNECT},
            )

        return self.async_abort(reason=ABORT_REASON_CANNOT_CONNECT)

    async def async_validate_connectable_bridge_config(self):
        """Check if we can connect to the bridge with the current config."""

        try:
            bridge = Smartbridge.create_tls(
                hostname=self.data[CONF_HOST],
                keyfile=self.data[CONF_KEYFILE],
                certfile=self.data[CONF_CERTFILE],
                ca_certs=self.data[CONF_CA_CERTS],
            )

            await bridge.connect()
            if not bridge.is_connected():
                return False

            await bridge.close()
            return True
        except Exception:  # pylint: disable=broad-except
            _LOGGER.exception(
                "Unknown exception while checking connectivity to bridge %s",
                self.data[CONF_HOST],
            )
            return False
