"""Adds config flow for Trafikverket Ferry integration."""

from collections.abc import Mapping
import logging
from typing import Any, override

from pytrafikverket import TrafikverketFerry
from pytrafikverket.exceptions import InvalidAuthentication, NoFerryFound
import voluptuous as vol

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_API_KEY, CONF_NAME, CONF_WEEKDAY, WEEKDAYS
from homeassistant.helpers import selector
from homeassistant.helpers.aiohttp_client import async_get_clientsession

from .const import CONF_FROM, CONF_TIME, CONF_TO, DOMAIN
from .util import create_unique_id

_LOGGER = logging.getLogger(__name__)

DATA_SCHEMA = vol.Schema(
    {
        vol.Required(CONF_API_KEY): selector.TextSelector(
            selector.TextSelectorConfig()
        ),
        vol.Required(CONF_FROM): selector.TextSelector(selector.TextSelectorConfig()),
        vol.Optional(CONF_TO): selector.TextSelector(selector.TextSelectorConfig()),
        vol.Optional(CONF_TIME): selector.TimeSelector(selector.TimeSelectorConfig()),
        vol.Required(CONF_WEEKDAY, default=WEEKDAYS): selector.SelectSelector(
            selector.SelectSelectorConfig(
                options=WEEKDAYS,
                multiple=True,
                mode=selector.SelectSelectorMode.DROPDOWN,
                translation_key=CONF_WEEKDAY,
            )
        ),
    }
)
DATA_SCHEMA_REAUTH = vol.Schema(
    {
        vol.Required(CONF_API_KEY): selector.TextSelector(
            selector.TextSelectorConfig()
        ),
    }
)


class TVFerryConfigFlow(ConfigFlow, domain=DOMAIN):
    """Handle a config flow for Trafikverket Ferry integration."""

    VERSION = 1

    async def validate_input(
        self, api_key: str, ferry_from: str, ferry_to: str
    ) -> None:
        """Validate input from user input."""
        web_session = async_get_clientsession(self.hass)
        ferry_api = TrafikverketFerry(web_session, api_key)
        await ferry_api.async_get_next_ferry_stop(ferry_from, ferry_to)

    async def async_step_reauth(
        self, entry_data: Mapping[str, Any]
    ) -> ConfigFlowResult:
        """Handle re-authentication with Trafikverket."""
        return await self.async_step_reauth_confirm()

    async def async_step_reauth_confirm(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Confirm re-authentication with Trafikverket."""
        errors: dict[str, str] = {}

        if user_input:
            api_key = user_input[CONF_API_KEY]

            reauth_entry = self._get_reauth_entry()
            try:
                await self.validate_input(
                    api_key, reauth_entry.data[CONF_FROM], reauth_entry.data[CONF_TO]
                )
            except InvalidAuthentication:
                errors["base"] = "invalid_auth"
            except NoFerryFound:
                errors["base"] = "invalid_route"
            except Exception:
                _LOGGER.exception("Unexpected exception")
                errors["base"] = "cannot_connect"
            else:
                return self.async_update_reload_and_abort(
                    reauth_entry,
                    data_updates={CONF_API_KEY: api_key},
                )

        return self.async_show_form(
            step_id="reauth_confirm",
            data_schema=DATA_SCHEMA_REAUTH,
            errors=errors,
        )

    @override
    async def async_step_user(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Handle the user step."""
        errors: dict[str, str] = {}

        if user_input is not None:
            api_key: str = user_input[CONF_API_KEY]
            ferry_from: str = user_input[CONF_FROM]
            ferry_to: str = user_input.get(CONF_TO, "")
            ferry_time: str = user_input[CONF_TIME]
            weekdays: list[str] = user_input[CONF_WEEKDAY]

            name = f"{ferry_from}"
            if ferry_to:
                name = name + f" to {ferry_to}"
            if ferry_time != "00:00:00":
                name = name + f" at {ferry_time!s}"

            try:
                await self.validate_input(api_key, ferry_from, ferry_to)
            except InvalidAuthentication:
                errors["base"] = "invalid_auth"
            except NoFerryFound:
                errors["base"] = "invalid_route"
            except Exception:
                _LOGGER.exception("Unexpected exception")
                errors["base"] = "cannot_connect"
            else:
                if not errors:
                    unique_id = create_unique_id(
                        ferry_from,
                        ferry_to,
                        ferry_time,
                        weekdays,
                    )
                    await self.async_set_unique_id(unique_id)
                    self._abort_if_unique_id_configured()
                    return self.async_create_entry(
                        title=name,
                        data={
                            CONF_API_KEY: api_key,
                            CONF_NAME: name,
                            CONF_FROM: ferry_from,
                            CONF_TO: ferry_to,
                            CONF_TIME: ferry_time,
                            CONF_WEEKDAY: weekdays,
                        },
                    )

        return self.async_show_form(
            step_id="user",
            data_schema=DATA_SCHEMA,
            errors=errors,
        )
