"""Test the Kuler Sky config flow."""

from unittest.mock import AsyncMock, Mock, patch

import pykulersky

from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
from homeassistant.components.kulersky.config_flow import DOMAIN
from homeassistant.config_entries import (
    SOURCE_BLUETOOTH,
    SOURCE_IGNORE,
    SOURCE_INTEGRATION_DISCOVERY,
    SOURCE_USER,
)
from homeassistant.const import CONF_ADDRESS
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType

from tests.common import MockConfigEntry
from tests.components.bluetooth import generate_advertisement_data, generate_ble_device

KULERSKY_SERVICE_INFO = BluetoothServiceInfoBleak(
    name="KulerLight",
    manufacturer_data={},
    service_data={},
    service_uuids=["8d96a001-0002-64c2-0001-9acc4838521c"],
    address="AA:BB:CC:DD:EE:FF",
    rssi=-60,
    source="local",
    advertisement=generate_advertisement_data(
        local_name="KulerLight",
        manufacturer_data={},
        service_data={},
        service_uuids=["8d96a001-0002-64c2-0001-9acc4838521c"],
    ),
    device=generate_ble_device("AA:BB:CC:DD:EE:FF", "KulerLight"),
    time=0,
    connectable=True,
    tx_power=-127,
)


async def test_bluetooth_discovery(hass: HomeAssistant) -> None:
    """Test discovery via bluetooth with a valid device."""
    result = await hass.config_entries.flow.async_init(
        DOMAIN,
        context={"source": SOURCE_BLUETOOTH},
        data=KULERSKY_SERVICE_INFO,
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "user"

    with patch("pykulersky.Light", Mock(return_value=AsyncMock())):
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_ADDRESS: "AA:BB:CC:DD:EE:FF"},
        )
    await hass.async_block_till_done()

    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["title"] == "KulerLight (EEFF)"
    assert result["data"] == {
        CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
    }


async def test_integration_discovery(hass: HomeAssistant) -> None:
    """Test discovery via bluetooth with a valid device."""
    with patch(
        "homeassistant.components.kulersky.config_flow.async_last_service_info",
        return_value=KULERSKY_SERVICE_INFO,
    ):
        result = await hass.config_entries.flow.async_init(
            DOMAIN,
            context={"source": SOURCE_INTEGRATION_DISCOVERY},
            data={CONF_ADDRESS: "AA:BB:CC:DD:EE:FF"},
        )

    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["title"] == "KulerLight (EEFF)"
    assert result["data"] == {
        CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
    }


async def test_integration_discovery_no_last_service_info(hass: HomeAssistant) -> None:
    """Test discovery via bluetooth with a valid device."""
    result = await hass.config_entries.flow.async_init(
        DOMAIN,
        context={"source": SOURCE_INTEGRATION_DISCOVERY},
        data={CONF_ADDRESS: "AA:BB:CC:DD:EE:FF"},
    )

    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["title"] == "AA:BB:CC:DD:EE:FF"
    assert result["data"] == {
        CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
    }


async def test_user_setup(hass: HomeAssistant) -> None:
    """Test the user manually setting up the integration."""
    with patch(
        "homeassistant.components.kulersky.config_flow.async_discovered_service_info",
        return_value=[
            KULERSKY_SERVICE_INFO,
            KULERSKY_SERVICE_INFO,
        ],  # Pass twice to test duplicate logic
    ):
        result = await hass.config_entries.flow.async_init(
            DOMAIN,
            context={"source": SOURCE_USER},
        )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "user"

    with patch("pykulersky.Light", Mock(return_value=AsyncMock())):
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_ADDRESS: "AA:BB:CC:DD:EE:FF"},
        )
    await hass.async_block_till_done()

    assert result["type"] is FlowResultType.CREATE_ENTRY
    assert result["title"] == "KulerLight (EEFF)"
    assert result["data"] == {
        CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
    }


async def test_user_setup_no_devices(hass: HomeAssistant) -> None:
    """Test the user manually setting up the integration."""
    with patch(
        "homeassistant.components.kulersky.config_flow.async_discovered_service_info",
        return_value=[],
    ):
        result = await hass.config_entries.flow.async_init(
            DOMAIN,
            context={"source": SOURCE_USER},
        )
    assert result["type"] is FlowResultType.ABORT
    assert result["reason"] == "no_devices_found"


async def test_connection_error(hass: HomeAssistant) -> None:
    """Test a connection error trying to set up."""
    result = await hass.config_entries.flow.async_init(
        DOMAIN,
        context={"source": SOURCE_BLUETOOTH},
        data=KULERSKY_SERVICE_INFO,
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "user"

    with patch("pykulersky.Light", Mock(side_effect=pykulersky.PykulerskyException)):
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_ADDRESS: "AA:BB:CC:DD:EE:FF"},
        )
    await hass.async_block_till_done()

    assert result["type"] is FlowResultType.FORM
    assert result["errors"]["base"] == "cannot_connect"


async def test_unexpected_error(hass: HomeAssistant) -> None:
    """Test an unexpected error trying to set up."""
    result = await hass.config_entries.flow.async_init(
        DOMAIN,
        context={"source": SOURCE_BLUETOOTH},
        data=KULERSKY_SERVICE_INFO,
    )
    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "user"

    with patch("pykulersky.Light", Mock(side_effect=Exception)):
        result = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_ADDRESS: "AA:BB:CC:DD:EE:FF"},
        )
    await hass.async_block_till_done()

    assert result["type"] is FlowResultType.FORM
    assert result["errors"]["base"] == "unknown"


async def test_user_setup_replaces_ignored_device(hass: HomeAssistant) -> None:
    """Test the user flow can replace an ignored device."""
    entry = MockConfigEntry(
        domain=DOMAIN,
        unique_id="AA:BB:CC:DD:EE:FF",
        source=SOURCE_IGNORE,
        data={},
    )
    entry.add_to_hass(hass)

    with patch(
        "homeassistant.components.kulersky.config_flow.async_discovered_service_info",
        return_value=[KULERSKY_SERVICE_INFO],
    ):
        result = await hass.config_entries.flow.async_init(
            DOMAIN,
            context={"source": SOURCE_USER},
        )
        await hass.async_block_till_done()

    assert result["type"] is FlowResultType.FORM
    assert result["step_id"] == "user"

    # Verify the ignored device is in the dropdown
    assert "AA:BB:CC:DD:EE:FF" in result["data_schema"].schema[CONF_ADDRESS].container

    with patch("pykulersky.Light", Mock(return_value=AsyncMock())):
        result2 = await hass.config_entries.flow.async_configure(
            result["flow_id"],
            {CONF_ADDRESS: "AA:BB:CC:DD:EE:FF"},
        )
        await hass.async_block_till_done()

    assert result2["type"] is FlowResultType.CREATE_ENTRY
    assert result2["title"] == "KulerLight (EEFF)"
    assert result2["data"] == {
        CONF_ADDRESS: "AA:BB:CC:DD:EE:FF",
    }
    assert result2["result"].unique_id == "AA:BB:CC:DD:EE:FF"
