"""Config flow for HVV integration."""
import logging

from pygti.auth import GTI_DEFAULT_HOST
from pygti.exceptions import CannotConnect, InvalidAuth
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.const import CONF_HOST, CONF_OFFSET, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client
import homeassistant.helpers.config_validation as cv

from .const import (  # pylint:disable=unused-import
    CONF_FILTER,
    CONF_REAL_TIME,
    CONF_STATION,
    DOMAIN,
)
from .hub import GTIHub

_LOGGER = logging.getLogger(__name__)

SCHEMA_STEP_USER = vol.Schema(
    {
        vol.Required(CONF_HOST, default=GTI_DEFAULT_HOST): str,
        vol.Required(CONF_USERNAME): str,
        vol.Required(CONF_PASSWORD): str,
    }
)

SCHEMA_STEP_STATION = vol.Schema({vol.Required(CONF_STATION): str})

SCHEMA_STEP_OPTIONS = vol.Schema(
    {
        vol.Required(CONF_FILTER): vol.In([]),
        vol.Required(CONF_OFFSET, default=0): vol.All(int, vol.Range(min=0)),
        vol.Optional(CONF_REAL_TIME, default=True): bool,
    }
)


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

    VERSION = 1
    CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL

    def __init__(self):
        """Initialize component."""
        self.hub = None
        self.data = None
        self.stations = {}

    async def async_step_user(self, user_input=None):
        """Handle the initial step."""
        errors = {}

        if user_input is not None:
            session = aiohttp_client.async_get_clientsession(self.hass)
            self.hub = GTIHub(
                user_input[CONF_HOST],
                user_input[CONF_USERNAME],
                user_input[CONF_PASSWORD],
                session,
            )

            try:
                response = await self.hub.authenticate()
                _LOGGER.debug("Init gti: %r", response)
            except CannotConnect:
                errors["base"] = "cannot_connect"
            except InvalidAuth:
                errors["base"] = "invalid_auth"

            if not errors:
                self.data = user_input
                return await self.async_step_station()

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

    async def async_step_station(self, user_input=None):
        """Handle the step where the user inputs his/her station."""
        if user_input is not None:

            errors = {}

            check_name = await self.hub.gti.checkName(
                {"theName": {"name": user_input[CONF_STATION]}, "maxList": 20}
            )

            stations = check_name.get("results")

            self.stations = {
                f"{station.get('name')}": station
                for station in stations
                if station.get("type") == "STATION"
            }

            if not self.stations:
                errors["base"] = "no_results"

                return self.async_show_form(
                    step_id="station", data_schema=SCHEMA_STEP_STATION, errors=errors
                )

            # schema

            return await self.async_step_station_select()

        return self.async_show_form(step_id="station", data_schema=SCHEMA_STEP_STATION)

    async def async_step_station_select(self, user_input=None):
        """Handle the step where the user inputs his/her station."""

        schema = vol.Schema({vol.Required(CONF_STATION): vol.In(list(self.stations))})

        if user_input is None:
            return self.async_show_form(step_id="station_select", data_schema=schema)

        self.data.update({"station": self.stations[user_input[CONF_STATION]]})

        title = self.data[CONF_STATION]["name"]

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

    @staticmethod
    @callback
    def async_get_options_flow(config_entry):
        """Get options flow."""
        return OptionsFlowHandler(config_entry)


class OptionsFlowHandler(config_entries.OptionsFlow):
    """Options flow handler."""

    def __init__(self, config_entry):
        """Initialize HVV Departures options flow."""
        self.config_entry = config_entry
        self.options = dict(config_entry.options)
        self.departure_filters = {}
        self.hub = None

    async def async_step_init(self, user_input=None):
        """Manage the options."""
        errors = {}
        if not self.departure_filters:

            departure_list = {}
            self.hub = self.hass.data[DOMAIN][self.config_entry.entry_id]

            try:
                departure_list = await self.hub.gti.departureList(
                    {
                        "station": self.config_entry.data[CONF_STATION],
                        "time": {"date": "heute", "time": "jetzt"},
                        "maxList": 5,
                        "maxTimeOffset": 200,
                        "useRealtime": True,
                        "returnFilters": True,
                    }
                )
            except CannotConnect:
                errors["base"] = "cannot_connect"
            except InvalidAuth:
                errors["base"] = "invalid_auth"

            if not errors:
                self.departure_filters = {
                    str(i): departure_filter
                    for i, departure_filter in enumerate(departure_list.get("filter"))
                }

        if user_input is not None and not errors:

            options = {
                CONF_FILTER: [
                    self.departure_filters[x] for x in user_input[CONF_FILTER]
                ],
                CONF_OFFSET: user_input[CONF_OFFSET],
                CONF_REAL_TIME: user_input[CONF_REAL_TIME],
            }

            return self.async_create_entry(title="", data=options)

        if CONF_FILTER in self.config_entry.options:
            old_filter = [
                i
                for (i, f) in self.departure_filters.items()
                if f in self.config_entry.options.get(CONF_FILTER)
            ]
        else:
            old_filter = []

        return self.async_show_form(
            step_id="init",
            data_schema=vol.Schema(
                {
                    vol.Optional(CONF_FILTER, default=old_filter): cv.multi_select(
                        {
                            key: f"{departure_filter['serviceName']}, {departure_filter['label']}"
                            for key, departure_filter in self.departure_filters.items()
                        }
                    ),
                    vol.Required(
                        CONF_OFFSET,
                        default=self.config_entry.options.get(CONF_OFFSET, 0),
                    ): vol.All(int, vol.Range(min=0)),
                    vol.Optional(
                        CONF_REAL_TIME,
                        default=self.config_entry.options.get(CONF_REAL_TIME, True),
                    ): bool,
                }
            ),
            errors=errors,
        )
