"""Config flow for Met Office integration."""

from __future__ import annotations

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

from datapoint.exceptions import APIException
from datapoint.Manager import Manager
from requests import HTTPError
import voluptuous as vol

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv

from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)


async def validate_input(
    hass: HomeAssistant, latitude: float, longitude: float, api_key: str
) -> dict[str, Any]:
    """Validate that the user input allows us to connect to DataPoint.

    Data has the keys from DATA_SCHEMA with values provided by the user.
    """
    errors = {}
    connection = Manager(api_key=api_key)

    try:
        forecast = await hass.async_add_executor_job(
            connection.get_forecast,
            latitude,
            longitude,
            "daily",
            False,
        )

    except (HTTPError, APIException) as err:
        if isinstance(err, HTTPError) and err.response.status_code == 401:
            errors["base"] = "invalid_auth"
        else:
            errors["base"] = "cannot_connect"
    except Exception:
        _LOGGER.exception("Unexpected exception")
        errors["base"] = "unknown"
    else:
        return {"site_name": forecast.name, "errors": errors}

    return {"errors": errors}


class MetOfficeConfigFlow(ConfigFlow, domain=DOMAIN):
    """Handle a config flow for Met Office weather integration."""

    VERSION = 1

    async def async_step_user(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Handle the initial step."""
        errors = {}
        if user_input is not None:
            await self.async_set_unique_id(
                f"{user_input[CONF_LATITUDE]}_{user_input[CONF_LONGITUDE]}"
            )
            self._abort_if_unique_id_configured()

            result = await validate_input(
                self.hass,
                latitude=user_input[CONF_LATITUDE],
                longitude=user_input[CONF_LONGITUDE],
                api_key=user_input[CONF_API_KEY],
            )

            errors = result["errors"]

            if not errors:
                user_input[CONF_NAME] = result["site_name"]
                return self.async_create_entry(
                    title=user_input[CONF_NAME], data=user_input
                )

        data_schema = vol.Schema(
            {
                vol.Required(CONF_API_KEY): str,
                vol.Required(
                    CONF_LATITUDE, default=self.hass.config.latitude
                ): cv.latitude,
                vol.Required(
                    CONF_LONGITUDE, default=self.hass.config.longitude
                ): cv.longitude,
            },
        )

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

    async def async_step_reauth(
        self, entry_data: Mapping[str, Any]
    ) -> ConfigFlowResult:
        """Perform reauth upon an API authentication error."""
        return await self.async_step_reauth_confirm()

    async def async_step_reauth_confirm(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Dialog that informs the user that reauth is required."""
        errors = {}

        entry = self._get_reauth_entry()
        if user_input is not None:
            result = await validate_input(
                self.hass,
                latitude=entry.data[CONF_LATITUDE],
                longitude=entry.data[CONF_LONGITUDE],
                api_key=user_input[CONF_API_KEY],
            )

            errors = result["errors"]

            if not errors:
                return self.async_update_reload_and_abort(
                    self._get_reauth_entry(),
                    data_updates=user_input,
                )

        return self.async_show_form(
            step_id="reauth_confirm",
            data_schema=vol.Schema(
                {
                    vol.Required(CONF_API_KEY): str,
                }
            ),
            description_placeholders={
                "docs_url": ("https://www.home-assistant.io/integrations/metoffice")
            },
            errors=errors,
        )


class CannotConnect(HomeAssistantError):
    """Error to indicate we cannot connect."""
