"""Config flow for bluesound."""

import logging
from typing import Any

import aiohttp
from pyblu import Player, SyncStatus
import voluptuous as vol

from homeassistant.components import zeroconf
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.helpers.aiohttp_client import async_get_clientsession

from .const import DOMAIN
from .media_player import DEFAULT_PORT
from .utils import format_unique_id

_LOGGER = logging.getLogger(__name__)


class BluesoundConfigFlow(ConfigFlow, domain=DOMAIN):
    """Bluesound config flow."""

    VERSION = 1
    MINOR_VERSION = 1

    def __init__(self) -> None:
        """Initialize the config flow."""
        self._host: str | None = None
        self._port = DEFAULT_PORT
        self._sync_status: SyncStatus | None = None

    async def async_step_user(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Handle a flow initiated by the user."""
        errors: dict[str, str] = {}
        if user_input is not None:
            session = async_get_clientsession(self.hass)
            async with Player(
                user_input[CONF_HOST], user_input[CONF_PORT], session=session
            ) as player:
                try:
                    sync_status = await player.sync_status(timeout=1)
                except (TimeoutError, aiohttp.ClientError):
                    errors["base"] = "cannot_connect"
                else:
                    await self.async_set_unique_id(
                        format_unique_id(sync_status.mac, user_input[CONF_PORT])
                    )
                    self._abort_if_unique_id_configured(
                        updates={
                            CONF_HOST: user_input[CONF_HOST],
                        }
                    )

                    return self.async_create_entry(
                        title=sync_status.name,
                        data=user_input,
                    )

        return self.async_show_form(
            step_id="user",
            errors=errors,
            data_schema=vol.Schema(
                {
                    vol.Required(CONF_HOST): str,
                    vol.Optional(CONF_PORT, default=11000): int,
                }
            ),
        )

    async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
        """Import bluesound config entry from configuration.yaml."""
        session = async_get_clientsession(self.hass)
        async with Player(
            import_data[CONF_HOST], import_data[CONF_PORT], session=session
        ) as player:
            try:
                sync_status = await player.sync_status(timeout=1)
            except (TimeoutError, aiohttp.ClientError):
                return self.async_abort(reason="cannot_connect")

        await self.async_set_unique_id(
            format_unique_id(sync_status.mac, import_data[CONF_PORT])
        )
        self._abort_if_unique_id_configured()

        return self.async_create_entry(
            title=sync_status.name,
            data=import_data,
        )

    async def async_step_zeroconf(
        self, discovery_info: zeroconf.ZeroconfServiceInfo
    ) -> ConfigFlowResult:
        """Handle a flow initialized by zeroconf discovery."""
        if discovery_info.port is not None:
            self._port = discovery_info.port

        session = async_get_clientsession(self.hass)
        try:
            async with Player(
                discovery_info.host, self._port, session=session
            ) as player:
                sync_status = await player.sync_status(timeout=1)
        except (TimeoutError, aiohttp.ClientError):
            return self.async_abort(reason="cannot_connect")

        await self.async_set_unique_id(format_unique_id(sync_status.mac, self._port))

        self._host = discovery_info.host
        self._sync_status = sync_status

        self._abort_if_unique_id_configured(
            updates={
                CONF_HOST: self._host,
            }
        )

        self.context.update(
            {
                "title_placeholders": {"name": sync_status.name},
                "configuration_url": f"http://{discovery_info.host}",
            }
        )
        return await self.async_step_confirm()

    async def async_step_confirm(self, user_input=None) -> ConfigFlowResult:
        """Confirm the zeroconf setup."""
        assert self._sync_status is not None
        assert self._host is not None

        if user_input is not None:
            return self.async_create_entry(
                title=self._sync_status.name,
                data={
                    CONF_HOST: self._host,
                    CONF_PORT: self._port,
                },
            )

        return self.async_show_form(
            step_id="confirm",
            description_placeholders={
                "name": self._sync_status.name,
                "host": self._host,
            },
        )
