"""Config flow for Sensoterra integration."""

from datetime import datetime, timedelta
from typing import Any, override

from jwt import DecodeError, decode
from sensoterra.customerapi import (
    CustomerApi,
    InvalidAuth as StInvalidAuth,
    Timeout as StTimeout,
)
import voluptuous as vol

from homeassistant.config_entries import SOURCE_USER, ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, CONF_TOKEN
from homeassistant.helpers.selector import (
    TextSelector,
    TextSelectorConfig,
    TextSelectorType,
)

from .const import DOMAIN, LOGGER, TOKEN_EXPIRATION_DAYS

STEP_USER_DATA_SCHEMA = vol.Schema(
    {
        vol.Required(CONF_EMAIL): TextSelector(
            TextSelectorConfig(type=TextSelectorType.EMAIL, autocomplete="email")
        ),
        vol.Required(CONF_PASSWORD): TextSelector(
            TextSelectorConfig(type=TextSelectorType.PASSWORD)
        ),
    }
)


class SensoterraConfigFlow(ConfigFlow, domain=DOMAIN):
    """Handle a config flow for Sensoterra."""

    @override
    async def async_step_user(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Create hub entry based on config flow."""
        errors: dict[str, str] = {}

        if user_input is not None:
            api = CustomerApi(user_input[CONF_EMAIL], user_input[CONF_PASSWORD])
            # We need a unique tag per HA instance
            uuid = self.hass.data["core.uuid"]
            expiration = datetime.now() + timedelta(TOKEN_EXPIRATION_DAYS)  # pylint: disable=home-assistant-enforce-naive-now

            try:
                token: str = await api.get_token(
                    f"Home Assistant {uuid}", "READONLY", expiration
                )
                decoded_token = decode(
                    token, algorithms=["HS256"], options={"verify_signature": False}
                )

            except StInvalidAuth as exp:
                LOGGER.error(
                    "Login attempt with %s: %s", user_input[CONF_EMAIL], exp.message
                )
                errors["base"] = "invalid_auth"
            except StTimeout:
                LOGGER.error("Login attempt with %s: time out", user_input[CONF_EMAIL])
                errors["base"] = "cannot_connect"
            except DecodeError:
                LOGGER.error("Login attempt with %s: bad token", user_input[CONF_EMAIL])
                errors["base"] = "invalid_access_token"
            else:
                device_unique_id = decoded_token["sub"]
                await self.async_set_unique_id(device_unique_id)
                self._abort_if_unique_id_configured()
                return self.async_create_entry(
                    title=user_input[CONF_EMAIL],
                    data={
                        CONF_TOKEN: token,
                        CONF_EMAIL: user_input[CONF_EMAIL],
                    },
                )

        return self.async_show_form(
            step_id=SOURCE_USER,
            data_schema=self.add_suggested_values_to_schema(
                STEP_USER_DATA_SCHEMA, user_input
            ),
            errors=errors,
        )
