"""Config flow for Ukraine Alarm."""
from __future__ import annotations

import asyncio
import logging

import aiohttp
from uasiren.client import Client
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.const import CONF_NAME, CONF_REGION
from homeassistant.helpers.aiohttp_client import async_get_clientsession

from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)


class UkraineAlarmConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
    """Config flow for Ukraine Alarm."""

    VERSION = 1

    def __init__(self):
        """Initialize a new UkraineAlarmConfigFlow."""
        self.states = None
        self.selected_region = None

    async def async_step_user(self, user_input=None):
        """Handle a flow initialized by the user."""

        if len(self._async_current_entries()) == 5:
            return self.async_abort(reason="max_regions")

        if not self.states:
            websession = async_get_clientsession(self.hass)
            reason = None
            unknown_err_msg = None
            try:
                regions = await Client(websession).get_regions()
            except aiohttp.ClientResponseError as ex:
                if ex.status == 429:
                    reason = "rate_limit"
                else:
                    reason = "unknown"
                    unknown_err_msg = str(ex)
            except aiohttp.ClientConnectionError:
                reason = "cannot_connect"
            except aiohttp.ClientError as ex:
                reason = "unknown"
                unknown_err_msg = str(ex)
            except asyncio.TimeoutError:
                reason = "timeout"

            if not reason and not regions:
                reason = "unknown"
                unknown_err_msg = "no regions returned"

            if unknown_err_msg:
                _LOGGER.error("Failed to connect to the service: %s", unknown_err_msg)

            if reason:
                return self.async_abort(reason=reason)
            self.states = regions["states"]

        return await self._handle_pick_region("user", "district", user_input)

    async def async_step_district(self, user_input=None):
        """Handle user-chosen district."""
        return await self._handle_pick_region("district", "community", user_input)

    async def async_step_community(self, user_input=None):
        """Handle user-chosen community."""
        return await self._handle_pick_region("community", None, user_input, True)

    async def _handle_pick_region(
        self, step_id: str, next_step: str | None, user_input, last_step=False
    ):
        """Handle picking a (sub)region."""
        if self.selected_region:
            source = self.selected_region["regionChildIds"]
        else:
            source = self.states

        if user_input is not None:
            # Only offer to browse subchildren if picked region wasn't the previously picked one
            if (
                not self.selected_region
                or user_input[CONF_REGION] != self.selected_region["regionId"]
            ):
                self.selected_region = _find(source, user_input[CONF_REGION])

                if next_step and self.selected_region["regionChildIds"]:
                    return await getattr(self, f"async_step_{next_step}")()

            return await self._async_finish_flow()

        regions = {}
        if self.selected_region:
            regions[self.selected_region["regionId"]] = self.selected_region[
                "regionName"
            ]

        regions.update(_make_regions_object(source))

        schema = vol.Schema(
            {
                vol.Required(CONF_REGION): vol.In(regions),
            }
        )

        return self.async_show_form(
            step_id=step_id, data_schema=schema, last_step=last_step
        )

    async def _async_finish_flow(self):
        """Finish the setup."""
        await self.async_set_unique_id(self.selected_region["regionId"])
        self._abort_if_unique_id_configured()

        return self.async_create_entry(
            title=self.selected_region["regionName"],
            data={
                CONF_REGION: self.selected_region["regionId"],
                CONF_NAME: self.selected_region["regionName"],
            },
        )


def _find(regions, region_id):
    return next((region for region in regions if region["regionId"] == region_id), None)


def _make_regions_object(regions):
    regions_list = []
    for region in regions:
        regions_list.append(
            {
                "id": region["regionId"],
                "name": region["regionName"],
            }
        )
    regions_list = sorted(regions_list, key=lambda region: region["name"].lower())
    regions_object = {}
    for region in regions_list:
        regions_object[region["id"]] = region["name"]

    return regions_object