"""Config flow to configure the LG Soundbar integration."""
import logging
from queue import Empty, Full, Queue
import socket

import temescal
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.data_entry_flow import FlowResult

from .const import DEFAULT_PORT, DOMAIN

DATA_SCHEMA = {
    vol.Required(CONF_HOST): str,
}

_LOGGER = logging.getLogger(__name__)

QUEUE_TIMEOUT = 10


def test_connect(host, port):
    """LG Soundbar config flow test_connect."""
    uuid_q = Queue(maxsize=1)
    name_q = Queue(maxsize=1)

    def check_msg_response(response, msgs, attr):
        msg = response["msg"]
        if msg == msgs or msg in msgs:
            if "data" in response and attr in response["data"]:
                return True
            _LOGGER.debug(
                "[%s] msg did not contain expected attr [%s]: %s", msg, attr, response
            )
        return False

    def queue_add(attr_q, data):
        try:
            attr_q.put_nowait(data)
        except Full:
            _LOGGER.debug("attempted to add [%s] to full queue", data)

    def msg_callback(response):
        if check_msg_response(response, ["MAC_INFO_DEV", "PRODUCT_INFO"], "s_uuid"):
            queue_add(uuid_q, response["data"]["s_uuid"])
        if check_msg_response(response, "SPK_LIST_VIEW_INFO", "s_user_name"):
            queue_add(name_q, response["data"]["s_user_name"])

    details = {}

    try:
        connection = temescal.temescal(host, port=port, callback=msg_callback)
        connection.get_info()
        connection.get_mac_info()
        if uuid_q.empty():
            connection.get_product_info()
        details["name"] = name_q.get(timeout=QUEUE_TIMEOUT)
        details["uuid"] = uuid_q.get(timeout=QUEUE_TIMEOUT)
    except Empty:
        pass
    except socket.timeout as err:
        raise ConnectionError(f"Connection timeout with server: {host}:{port}") from err
    except OSError as err:
        raise ConnectionError(f"Cannot resolve hostname: {host}") from err

    return details


class LGSoundbarConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
    """LG Soundbar config flow."""

    VERSION = 1

    async def async_step_user(self, user_input=None) -> FlowResult:
        """Handle a flow initiated by the user."""
        if user_input is None:
            return self._show_form()

        errors = {}
        try:
            details = await self.hass.async_add_executor_job(
                test_connect, user_input[CONF_HOST], DEFAULT_PORT
            )
        except ConnectionError:
            errors["base"] = "cannot_connect"
        else:
            if len(details) != 0:
                info = {
                    CONF_HOST: user_input[CONF_HOST],
                    CONF_PORT: DEFAULT_PORT,
                }
                if "uuid" in details:
                    unique_id = details["uuid"]
                    await self.async_set_unique_id(unique_id)
                    self._abort_if_unique_id_configured()
                else:
                    self._async_abort_entries_match(info)
                return self.async_create_entry(title=details["name"], data=info)
            errors["base"] = "no_data"

        return self._show_form(errors)

    def _show_form(self, errors=None):
        """Show the form to the user."""
        return self.async_show_form(
            step_id="user",
            data_schema=vol.Schema(DATA_SCHEMA),
            errors=errors if errors else {},
        )
