"""deCONZ light platform tests."""
from unittest.mock import patch

import pytest

from homeassistant.components.deconz.const import ATTR_ON, CONF_ALLOW_DECONZ_GROUPS
from homeassistant.components.deconz.light import DECONZ_GROUP
from homeassistant.components.light import (
    ATTR_BRIGHTNESS,
    ATTR_COLOR_MODE,
    ATTR_COLOR_TEMP,
    ATTR_EFFECT,
    ATTR_EFFECT_LIST,
    ATTR_FLASH,
    ATTR_HS_COLOR,
    ATTR_MAX_MIREDS,
    ATTR_MIN_MIREDS,
    ATTR_RGB_COLOR,
    ATTR_SUPPORTED_COLOR_MODES,
    ATTR_TRANSITION,
    ATTR_XY_COLOR,
    DOMAIN as LIGHT_DOMAIN,
    EFFECT_COLORLOOP,
    FLASH_LONG,
    FLASH_SHORT,
    SERVICE_TURN_OFF,
    SERVICE_TURN_ON,
    ColorMode,
    LightEntityFeature,
)
from homeassistant.const import (
    ATTR_ENTITY_ID,
    ATTR_SUPPORTED_FEATURES,
    STATE_OFF,
    STATE_ON,
    STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant

from .test_gateway import (
    DECONZ_WEB_REQUEST,
    mock_deconz_put_request,
    setup_deconz_integration,
)

from tests.test_util.aiohttp import AiohttpClientMocker


async def test_no_lights_or_groups(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
    """Test that no lights or groups entities are created."""
    await setup_deconz_integration(hass, aioclient_mock)
    assert len(hass.states.async_all()) == 0


@pytest.mark.parametrize(
    "input,expected",
    [
        (  # RGB light in color temp color mode
            {
                "colorcapabilities": 31,
                "ctmax": 500,
                "ctmin": 153,
                "etag": "055485a82553e654f156d41c9301b7cf",
                "hascolor": True,
                "lastannounced": None,
                "lastseen": "2021-06-10T20:25Z",
                "manufacturername": "Philips",
                "modelid": "LLC020",
                "name": "Hue Go",
                "state": {
                    "alert": "none",
                    "bri": 254,
                    "colormode": "ct",
                    "ct": 375,
                    "effect": "none",
                    "hue": 8348,
                    "on": True,
                    "reachable": True,
                    "sat": 147,
                    "xy": [0.462, 0.4111],
                },
                "swversion": "5.127.1.26420",
                "type": "Extended color light",
                "uniqueid": "00:17:88:01:01:23:45:67-00",
            },
            {
                "entity_id": "light.hue_go",
                "state": STATE_ON,
                "attributes": {
                    ATTR_BRIGHTNESS: 254,
                    ATTR_COLOR_TEMP: 375,
                    ATTR_EFFECT_LIST: [EFFECT_COLORLOOP],
                    ATTR_SUPPORTED_COLOR_MODES: [
                        ColorMode.COLOR_TEMP,
                        ColorMode.HS,
                        ColorMode.XY,
                    ],
                    ATTR_COLOR_MODE: ColorMode.COLOR_TEMP,
                    ATTR_MIN_MIREDS: 153,
                    ATTR_MAX_MIREDS: 500,
                    ATTR_SUPPORTED_FEATURES: LightEntityFeature.TRANSITION
                    | LightEntityFeature.FLASH
                    | LightEntityFeature.EFFECT,
                    DECONZ_GROUP: False,
                },
            },
        ),
        (  # RGB light in XY color mode
            {
                "colorcapabilities": 0,
                "ctmax": 65535,
                "ctmin": 0,
                "etag": "74c91da78bbb5f4dc4d36edf4ad6857c",
                "hascolor": True,
                "lastannounced": "2021-01-27T18:05:38Z",
                "lastseen": "2021-06-10T20:26Z",
                "manufacturername": "Philips",
                "modelid": "4090331P9_01",
                "name": "Hue Ensis",
                "state": {
                    "alert": "none",
                    "bri": 254,
                    "colormode": "xy",
                    "ct": 316,
                    "effect": "0",
                    "hue": 3096,
                    "on": True,
                    "reachable": True,
                    "sat": 48,
                    "xy": [0.427, 0.373],
                },
                "swversion": "1.65.9_hB3217DF4",
                "type": "Extended color light",
                "uniqueid": "00:17:88:01:01:23:45:67-01",
            },
            {
                "entity_id": "light.hue_ensis",
                "state": STATE_ON,
                "attributes": {
                    ATTR_MIN_MIREDS: 140,
                    ATTR_MAX_MIREDS: 650,
                    ATTR_EFFECT_LIST: [EFFECT_COLORLOOP],
                    ATTR_SUPPORTED_COLOR_MODES: [
                        ColorMode.COLOR_TEMP,
                        ColorMode.HS,
                        ColorMode.XY,
                    ],
                    ATTR_COLOR_MODE: ColorMode.XY,
                    ATTR_BRIGHTNESS: 254,
                    ATTR_HS_COLOR: (29.691, 38.039),
                    ATTR_RGB_COLOR: (255, 206, 158),
                    ATTR_XY_COLOR: (0.427, 0.373),
                    DECONZ_GROUP: False,
                    ATTR_SUPPORTED_FEATURES: LightEntityFeature.TRANSITION
                    | LightEntityFeature.FLASH
                    | LightEntityFeature.EFFECT,
                },
            },
        ),
        (  # RGB light with only HS color mode
            {
                "etag": "87a89542bf9b9d0aa8134919056844f8",
                "hascolor": True,
                "lastannounced": None,
                "lastseen": "2020-12-05T22:57Z",
                "manufacturername": "_TZE200_s8gkrkxk",
                "modelid": "TS0601",
                "name": "LIDL xmas light",
                "state": {
                    "bri": 25,
                    "colormode": "hs",
                    "effect": "none",
                    "hue": 53691,
                    "on": True,
                    "reachable": True,
                    "sat": 141,
                },
                "swversion": None,
                "type": "Color dimmable light",
                "uniqueid": "58:8e:81:ff:fe:db:7b:be-01",
            },
            {
                "entity_id": "light.lidl_xmas_light",
                "state": STATE_ON,
                "attributes": {
                    ATTR_EFFECT_LIST: [EFFECT_COLORLOOP],
                    ATTR_SUPPORTED_COLOR_MODES: [ColorMode.HS],
                    ATTR_COLOR_MODE: ColorMode.HS,
                    ATTR_BRIGHTNESS: 25,
                    ATTR_HS_COLOR: (294.938, 55.294),
                    ATTR_RGB_COLOR: (243, 113, 255),
                    ATTR_XY_COLOR: (0.357, 0.188),
                    DECONZ_GROUP: False,
                    ATTR_SUPPORTED_FEATURES: LightEntityFeature.TRANSITION
                    | LightEntityFeature.FLASH
                    | LightEntityFeature.EFFECT,
                },
            },
        ),
        (  # Tunable white light in CT color mode
            {
                "colorcapabilities": 16,
                "ctmax": 454,
                "ctmin": 153,
                "etag": "576ffecbedb4abdc3d3f375fd8f17a9e",
                "hascolor": True,
                "lastannounced": None,
                "lastseen": "2021-06-10T20:25Z",
                "manufacturername": "Philips",
                "modelid": "LTW013",
                "name": "Hue White Ambiance",
                "state": {
                    "alert": "none",
                    "bri": 254,
                    "colormode": "ct",
                    "ct": 396,
                    "on": True,
                    "reachable": True,
                },
                "swversion": "1.46.13_r26312",
                "type": "Color temperature light",
                "uniqueid": "00:17:88:01:01:23:45:67-02",
            },
            {
                "entity_id": "light.hue_white_ambiance",
                "state": STATE_ON,
                "attributes": {
                    ATTR_MIN_MIREDS: 153,
                    ATTR_MAX_MIREDS: 454,
                    ATTR_SUPPORTED_COLOR_MODES: [ColorMode.COLOR_TEMP],
                    ATTR_COLOR_MODE: ColorMode.COLOR_TEMP,
                    ATTR_BRIGHTNESS: 254,
                    ATTR_COLOR_TEMP: 396,
                    DECONZ_GROUP: False,
                    ATTR_SUPPORTED_FEATURES: LightEntityFeature.TRANSITION
                    | LightEntityFeature.FLASH,
                },
            },
        ),
        (  # Dimmable light
            {
                "etag": "f88e87235e2abce62404edd99b1af323",
                "hascolor": False,
                "lastannounced": None,
                "lastseen": "2021-06-10T20:26Z",
                "manufacturername": "Philips",
                "modelid": "LWO001",
                "name": "Hue Filament",
                "state": {"alert": "none", "bri": 254, "on": True, "reachable": True},
                "swversion": "1.55.8_r28815",
                "type": "Dimmable light",
                "uniqueid": "00:17:88:01:01:23:45:67-03",
            },
            {
                "entity_id": "light.hue_filament",
                "state": STATE_ON,
                "attributes": {
                    ATTR_SUPPORTED_COLOR_MODES: [ColorMode.BRIGHTNESS],
                    ATTR_COLOR_MODE: ColorMode.BRIGHTNESS,
                    ATTR_BRIGHTNESS: 254,
                    DECONZ_GROUP: False,
                    ATTR_SUPPORTED_FEATURES: LightEntityFeature.TRANSITION
                    | LightEntityFeature.FLASH,
                },
            },
        ),
        (  # On/Off light
            {
                "etag": "99c67fd8f0529c6c2aab94b45e4f6caa",
                "hascolor": False,
                "lastannounced": "2021-04-26T20:28:11Z",
                "lastseen": "2021-06-10T21:15Z",
                "manufacturername": "Unknown",
                "modelid": "Unknown",
                "name": "Simple Light",
                "state": {"alert": "none", "on": True, "reachable": True},
                "swversion": "2.0",
                "type": "Simple light",
                "uniqueid": "00:15:8d:00:01:23:45:67-01",
            },
            {
                "entity_id": "light.simple_light",
                "state": STATE_ON,
                "attributes": {
                    ATTR_SUPPORTED_COLOR_MODES: [ColorMode.ONOFF],
                    ATTR_COLOR_MODE: ColorMode.ONOFF,
                    DECONZ_GROUP: False,
                    ATTR_SUPPORTED_FEATURES: 0,
                },
            },
        ),
    ],
)
async def test_lights(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, input, expected
) -> None:
    """Test that different light entities are created with expected values."""
    data = {"lights": {"0": input}}
    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(hass, aioclient_mock)

    assert len(hass.states.async_all()) == 1

    light = hass.states.get(expected["entity_id"])
    assert light.state == expected["state"]
    for attribute, expected_value in expected["attributes"].items():
        assert light.attributes[attribute] == expected_value

    await hass.config_entries.async_unload(config_entry.entry_id)

    states = hass.states.async_all()
    for state in states:
        assert state.state == STATE_UNAVAILABLE

    await hass.config_entries.async_remove(config_entry.entry_id)
    await hass.async_block_till_done()
    assert len(hass.states.async_all()) == 0


async def test_light_state_change(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_deconz_websocket
) -> None:
    """Verify light can change state on websocket event."""
    data = {
        "lights": {
            "0": {
                "colorcapabilities": 31,
                "ctmax": 500,
                "ctmin": 153,
                "etag": "055485a82553e654f156d41c9301b7cf",
                "hascolor": True,
                "lastannounced": None,
                "lastseen": "2021-06-10T20:25Z",
                "manufacturername": "Philips",
                "modelid": "LLC020",
                "name": "Hue Go",
                "state": {
                    "alert": "none",
                    "bri": 254,
                    "colormode": "ct",
                    "ct": 375,
                    "effect": "none",
                    "hue": 8348,
                    "on": True,
                    "reachable": True,
                    "sat": 147,
                    "xy": [0.462, 0.4111],
                },
                "swversion": "5.127.1.26420",
                "type": "Extended color light",
                "uniqueid": "00:17:88:01:01:23:45:67-00",
            }
        }
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        await setup_deconz_integration(hass, aioclient_mock)

    assert hass.states.get("light.hue_go").state == STATE_ON

    event_changed_light = {
        "t": "event",
        "e": "changed",
        "r": "lights",
        "id": "0",
        "state": {"on": False},
    }
    await mock_deconz_websocket(data=event_changed_light)
    await hass.async_block_till_done()

    assert hass.states.get("light.hue_go").state == STATE_OFF


@pytest.mark.parametrize(
    "input,expected",
    [
        (  # Turn on light with hue and sat
            {
                "light_on": True,
                "service": SERVICE_TURN_ON,
                "call": {
                    ATTR_ENTITY_ID: "light.hue_go",
                    ATTR_HS_COLOR: (20, 30),
                },
            },
            {
                "on": True,
                "xy": (0.411, 0.351),
            },
        ),
        (  # Turn on light with XY color
            {
                "light_on": True,
                "service": SERVICE_TURN_ON,
                "call": {
                    ATTR_ENTITY_ID: "light.hue_go",
                    ATTR_XY_COLOR: (0.411, 0.351),
                },
            },
            {
                "on": True,
                "xy": (0.411, 0.351),
            },
        ),
        (  # Turn on light without transition time
            {
                "light_on": True,
                "service": SERVICE_TURN_ON,
                "call": {
                    ATTR_ENTITY_ID: "light.hue_go",
                    ATTR_TRANSITION: 0,
                },
            },
            {
                "on": True,
                "transitiontime": 0,
            },
        ),
        (  # Turn on light with short color loop
            {
                "light_on": False,
                "service": SERVICE_TURN_ON,
                "call": {
                    ATTR_ENTITY_ID: "light.hue_go",
                    ATTR_BRIGHTNESS: 200,
                    ATTR_COLOR_TEMP: 200,
                    ATTR_TRANSITION: 5,
                    ATTR_FLASH: FLASH_SHORT,
                    ATTR_EFFECT: EFFECT_COLORLOOP,
                },
            },
            {
                "bri": 200,
                "ct": 200,
                "transitiontime": 50,
                "alert": "select",
                "effect": "colorloop",
            },
        ),
        (  # Turn on light disabling color loop with long flashing
            {
                "light_on": False,
                "service": SERVICE_TURN_ON,
                "call": {
                    ATTR_ENTITY_ID: "light.hue_go",
                    ATTR_XY_COLOR: (0.411, 0.351),
                    ATTR_FLASH: FLASH_LONG,
                    ATTR_EFFECT: "None",
                },
            },
            {
                "xy": (0.411, 0.351),
                "alert": "lselect",
                "effect": "none",
            },
        ),
        (  # Turn off light with short flashing
            {
                "light_on": True,
                "service": SERVICE_TURN_OFF,
                "call": {
                    ATTR_ENTITY_ID: "light.hue_go",
                    ATTR_TRANSITION: 5,
                    ATTR_FLASH: FLASH_SHORT,
                },
            },
            {
                "bri": 0,
                "transitiontime": 50,
                "alert": "select",
            },
        ),
        (  # Turn off light without transition time
            {
                "light_on": True,
                "service": SERVICE_TURN_OFF,
                "call": {
                    ATTR_ENTITY_ID: "light.hue_go",
                    ATTR_TRANSITION: 0,
                    ATTR_FLASH: FLASH_SHORT,
                },
            },
            {
                "bri": 0,
                "transitiontime": 0,
                "alert": "select",
            },
        ),
        (  # Turn off light with long flashing
            {
                "light_on": True,
                "service": SERVICE_TURN_OFF,
                "call": {ATTR_ENTITY_ID: "light.hue_go", ATTR_FLASH: FLASH_LONG},
            },
            {"alert": "lselect"},
        ),
        (  # Turn off light when light is already off is not supported
            {
                "light_on": False,
                "service": SERVICE_TURN_OFF,
                "call": {
                    ATTR_ENTITY_ID: "light.hue_go",
                    ATTR_TRANSITION: 5,
                    ATTR_FLASH: FLASH_SHORT,
                },
            },
            {},
        ),
    ],
)
async def test_light_service_calls(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, input, expected
) -> None:
    """Verify light can change state on websocket event."""
    data = {
        "lights": {
            "0": {
                "colorcapabilities": 31,
                "ctmax": 500,
                "ctmin": 153,
                "etag": "055485a82553e654f156d41c9301b7cf",
                "hascolor": True,
                "lastannounced": None,
                "lastseen": "2021-06-10T20:25Z",
                "manufacturername": "Philips",
                "modelid": "LLC020",
                "name": "Hue Go",
                "state": {
                    "alert": "none",
                    "bri": 254,
                    "colormode": "ct",
                    "ct": 375,
                    "effect": "none",
                    "hue": 8348,
                    "on": input["light_on"],
                    "reachable": True,
                    "sat": 147,
                    "xy": [0.462, 0.4111],
                },
                "swversion": "5.127.1.26420",
                "type": "Extended color light",
                "uniqueid": "00:17:88:01:01:23:45:67-00",
            }
        }
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(hass, aioclient_mock)

    mock_deconz_put_request(aioclient_mock, config_entry.data, "/lights/0/state")

    await hass.services.async_call(
        LIGHT_DOMAIN,
        input["service"],
        input["call"],
        blocking=True,
    )
    if expected:
        assert aioclient_mock.mock_calls[1][2] == expected
    else:
        assert len(aioclient_mock.mock_calls) == 1  # not called


async def test_ikea_default_transition_time(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
    """Verify that service calls to IKEA lights always extend with transition tinme 0 if absent."""
    data = {
        "lights": {
            "0": {
                "colorcapabilities": 0,
                "ctmax": 65535,
                "ctmin": 0,
                "etag": "9dd510cd474791481f189d2a68a3c7f1",
                "hascolor": True,
                "lastannounced": "2020-12-17T17:44:38Z",
                "lastseen": "2021-01-11T18:36Z",
                "manufacturername": "IKEA of Sweden",
                "modelid": "TRADFRI bulb E27 WS opal 1000lm",
                "name": "IKEA light",
                "state": {
                    "alert": "none",
                    "bri": 156,
                    "colormode": "ct",
                    "ct": 250,
                    "on": True,
                    "reachable": True,
                },
                "swversion": "2.0.022",
                "type": "Color temperature light",
                "uniqueid": "ec:1b:bd:ff:fe:ee:ed:dd-01",
            },
        },
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(hass, aioclient_mock)

    mock_deconz_put_request(aioclient_mock, config_entry.data, "/lights/0/state")

    await hass.services.async_call(
        LIGHT_DOMAIN,
        SERVICE_TURN_ON,
        {
            ATTR_ENTITY_ID: "light.ikea_light",
            ATTR_BRIGHTNESS: 100,
        },
        blocking=True,
    )
    assert aioclient_mock.mock_calls[1][2] == {
        "bri": 100,
        "on": True,
        "transitiontime": 0,
    }

    await hass.services.async_call(
        LIGHT_DOMAIN,
        SERVICE_TURN_ON,
        {
            ATTR_ENTITY_ID: "light.ikea_light",
            ATTR_BRIGHTNESS: 100,
            ATTR_TRANSITION: 5,
        },
        blocking=True,
    )
    assert aioclient_mock.mock_calls[2][2] == {
        "bri": 100,
        "on": True,
        "transitiontime": 50,
    }


async def test_lidl_christmas_light(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
    """Test that lights or groups entities are created."""
    data = {
        "lights": {
            "0": {
                "etag": "87a89542bf9b9d0aa8134919056844f8",
                "hascolor": True,
                "lastannounced": None,
                "lastseen": "2020-12-05T22:57Z",
                "manufacturername": "_TZE200_s8gkrkxk",
                "modelid": "TS0601",
                "name": "LIDL xmas light",
                "state": {
                    "bri": 25,
                    "colormode": "hs",
                    "effect": "none",
                    "hue": 53691,
                    "on": True,
                    "reachable": True,
                    "sat": 141,
                },
                "swversion": None,
                "type": "Color dimmable light",
                "uniqueid": "58:8e:81:ff:fe:db:7b:be-01",
            }
        }
    }

    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(hass, aioclient_mock)

    mock_deconz_put_request(aioclient_mock, config_entry.data, "/lights/0/state")

    await hass.services.async_call(
        LIGHT_DOMAIN,
        SERVICE_TURN_ON,
        {
            ATTR_ENTITY_ID: "light.lidl_xmas_light",
            ATTR_HS_COLOR: (20, 30),
        },
        blocking=True,
    )
    assert aioclient_mock.mock_calls[1][2] == {"on": True, "hue": 3640, "sat": 76}

    assert hass.states.get("light.lidl_xmas_light")


async def test_configuration_tool(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
    """Verify that configuration tool is not created."""
    data = {
        "lights": {
            "0": {
                "etag": "26839cb118f5bf7ba1f2108256644010",
                "hascolor": False,
                "lastannounced": None,
                "lastseen": "2020-11-22T11:27Z",
                "manufacturername": "dresden elektronik",
                "modelid": "ConBee II",
                "name": "Configuration tool 1",
                "state": {"reachable": True},
                "swversion": "0x264a0700",
                "type": "Configuration tool",
                "uniqueid": "00:21:2e:ff:ff:05:a7:a3-01",
            }
        }
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        await setup_deconz_integration(hass, aioclient_mock)

    assert len(hass.states.async_all()) == 0


@pytest.mark.parametrize(
    "input,expected",
    [
        (
            {
                "lights": ["1", "2", "3"],
            },
            {
                "entity_id": "light.group",
                "state": ATTR_ON,
                "attributes": {
                    ATTR_MIN_MIREDS: 153,
                    ATTR_MAX_MIREDS: 500,
                    ATTR_SUPPORTED_COLOR_MODES: [ColorMode.COLOR_TEMP, ColorMode.XY],
                    ATTR_COLOR_MODE: ColorMode.COLOR_TEMP,
                    ATTR_BRIGHTNESS: 255,
                    ATTR_EFFECT_LIST: [EFFECT_COLORLOOP],
                    "all_on": False,
                    DECONZ_GROUP: True,
                    ATTR_SUPPORTED_FEATURES: 44,
                },
            },
        ),
        (
            {
                "lights": ["3", "1", "2"],
            },
            {
                "entity_id": "light.group",
                "state": ATTR_ON,
                "attributes": {
                    ATTR_MIN_MIREDS: 153,
                    ATTR_MAX_MIREDS: 500,
                    ATTR_SUPPORTED_COLOR_MODES: [ColorMode.COLOR_TEMP, ColorMode.XY],
                    ATTR_COLOR_MODE: ColorMode.COLOR_TEMP,
                    ATTR_BRIGHTNESS: 50,
                    ATTR_EFFECT_LIST: [EFFECT_COLORLOOP],
                    "all_on": False,
                    DECONZ_GROUP: True,
                    ATTR_SUPPORTED_FEATURES: LightEntityFeature.TRANSITION
                    | LightEntityFeature.FLASH
                    | LightEntityFeature.EFFECT,
                },
            },
        ),
        (
            {
                "lights": ["2", "3", "1"],
            },
            {
                "entity_id": "light.group",
                "state": ATTR_ON,
                "attributes": {
                    ATTR_MIN_MIREDS: 153,
                    ATTR_MAX_MIREDS: 500,
                    ATTR_SUPPORTED_COLOR_MODES: [ColorMode.COLOR_TEMP, ColorMode.XY],
                    ATTR_COLOR_MODE: ColorMode.XY,
                    ATTR_HS_COLOR: (52.0, 100.0),
                    ATTR_RGB_COLOR: (255, 221, 0),
                    ATTR_XY_COLOR: (0.5, 0.5),
                    "all_on": False,
                    DECONZ_GROUP: True,
                    ATTR_SUPPORTED_FEATURES: LightEntityFeature.TRANSITION
                    | LightEntityFeature.FLASH
                    | LightEntityFeature.EFFECT,
                },
            },
        ),
    ],
)
async def test_groups(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, input, expected
) -> None:
    """Test that different group entities are created with expected values."""
    data = {
        "groups": {
            "0": {
                "id": "Light group id",
                "name": "Group",
                "type": "LightGroup",
                "state": {"all_on": False, "any_on": True},
                "action": {
                    "alert": "none",
                    "bri": 127,
                    "colormode": "hs",
                    "ct": 0,
                    "effect": "none",
                    "hue": 0,
                    "on": True,
                    "sat": 127,
                    "scene": None,
                    "xy": [0, 0],
                },
                "scenes": [],
                "lights": input["lights"],
            },
        },
        "lights": {
            "1": {
                "name": "RGB light",
                "state": {
                    "on": True,
                    "bri": 50,
                    "colormode": "xy",
                    "effect": "colorloop",
                    "xy": (0.5, 0.5),
                    "reachable": True,
                },
                "type": "Extended color light",
                "uniqueid": "00:00:00:00:00:00:00:00-00",
            },
            "2": {
                "ctmax": 454,
                "ctmin": 155,
                "name": "Tunable white light",
                "state": {
                    "on": True,
                    "colormode": "ct",
                    "ct": 2500,
                    "reachable": True,
                },
                "type": "Tunable white light",
                "uniqueid": "00:00:00:00:00:00:00:01-00",
            },
            "3": {
                "name": "Dimmable light",
                "type": "Dimmable light",
                "state": {"bri": 255, "on": True, "reachable": True},
                "uniqueid": "00:00:00:00:00:00:00:02-00",
            },
        },
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(hass, aioclient_mock)

    assert len(hass.states.async_all()) == 4

    group = hass.states.get(expected["entity_id"])
    assert group.state == expected["state"]
    for attribute, expected_value in expected["attributes"].items():
        assert group.attributes[attribute] == expected_value

    await hass.config_entries.async_unload(config_entry.entry_id)

    states = hass.states.async_all()
    for state in states:
        assert state.state == STATE_UNAVAILABLE

    await hass.config_entries.async_remove(config_entry.entry_id)
    await hass.async_block_till_done()
    assert len(hass.states.async_all()) == 0


@pytest.mark.parametrize(
    "input,expected",
    [
        (  # Turn on group with short color loop
            {
                "lights": ["1", "2", "3"],
                "group_on": False,
                "service": SERVICE_TURN_ON,
                "call": {
                    ATTR_ENTITY_ID: "light.group",
                    ATTR_BRIGHTNESS: 200,
                    ATTR_COLOR_TEMP: 200,
                    ATTR_TRANSITION: 5,
                    ATTR_FLASH: FLASH_SHORT,
                    ATTR_EFFECT: EFFECT_COLORLOOP,
                },
            },
            {
                "bri": 200,
                "ct": 200,
                "transitiontime": 50,
                "alert": "select",
                "effect": "colorloop",
            },
        ),
        (  # Turn on group with hs colors
            {
                "lights": ["1", "2", "3"],
                "group_on": False,
                "service": SERVICE_TURN_ON,
                "call": {
                    ATTR_ENTITY_ID: "light.group",
                    ATTR_HS_COLOR: (250, 50),
                },
            },
            {
                "on": True,
                "xy": (0.235, 0.164),
            },
        ),
        (  # Turn on group with short color loop
            {
                "lights": ["3", "2", "1"],
                "group_on": False,
                "service": SERVICE_TURN_ON,
                "call": {
                    ATTR_ENTITY_ID: "light.group",
                    ATTR_HS_COLOR: (250, 50),
                },
            },
            {
                "on": True,
                "xy": (0.235, 0.164),
            },
        ),
    ],
)
async def test_group_service_calls(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, input, expected
) -> None:
    """Verify expected group web request from different service calls."""
    data = {
        "groups": {
            "0": {
                "id": "Light group id",
                "name": "Group",
                "type": "LightGroup",
                "state": {"all_on": False, "any_on": input["group_on"]},
                "action": {},
                "scenes": [],
                "lights": input["lights"],
            },
        },
        "lights": {
            "1": {
                "name": "RGB light",
                "state": {
                    "bri": 255,
                    "colormode": "xy",
                    "effect": "colorloop",
                    "hue": 53691,
                    "on": True,
                    "reachable": True,
                    "sat": 141,
                    "xy": (0.5, 0.5),
                },
                "type": "Extended color light",
                "uniqueid": "00:00:00:00:00:00:00:00-00",
            },
            "2": {
                "ctmax": 454,
                "ctmin": 155,
                "name": "Tunable white light",
                "state": {
                    "on": True,
                    "colormode": "ct",
                    "ct": 2500,
                    "reachable": True,
                },
                "type": "Tunable white light",
                "uniqueid": "00:00:00:00:00:00:00:01-00",
            },
            "3": {
                "name": "Dimmable light",
                "type": "Dimmable light",
                "state": {"bri": 254, "on": True, "reachable": True},
                "uniqueid": "00:00:00:00:00:00:00:02-00",
            },
        },
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(hass, aioclient_mock)

    mock_deconz_put_request(aioclient_mock, config_entry.data, "/groups/0/action")

    await hass.services.async_call(
        LIGHT_DOMAIN,
        input["service"],
        input["call"],
        blocking=True,
    )
    if expected:
        assert aioclient_mock.mock_calls[1][2] == expected
    else:
        assert len(aioclient_mock.mock_calls) == 1  # not called


async def test_empty_group(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
    """Verify that a group without a list of lights is not created."""
    data = {
        "groups": {
            "0": {
                "id": "Empty group id",
                "name": "Empty group",
                "type": "LightGroup",
                "state": {},
                "action": {},
                "scenes": [],
                "lights": [],
            },
        },
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        await setup_deconz_integration(hass, aioclient_mock)

    assert len(hass.states.async_all()) == 0
    assert not hass.states.get("light.empty_group")


async def test_disable_light_groups(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
    """Test disallowing light groups work."""
    data = {
        "groups": {
            "1": {
                "id": "Light group id",
                "name": "Light group",
                "type": "LightGroup",
                "state": {"all_on": False, "any_on": True},
                "action": {},
                "scenes": [],
                "lights": ["1"],
            },
            "2": {
                "id": "Empty group id",
                "name": "Empty group",
                "type": "LightGroup",
                "state": {},
                "action": {},
                "scenes": [],
                "lights": [],
            },
        },
        "lights": {
            "1": {
                "ctmax": 454,
                "ctmin": 155,
                "name": "Tunable white light",
                "state": {"on": True, "colormode": "ct", "ct": 2500, "reachable": True},
                "type": "Tunable white light",
                "uniqueid": "00:00:00:00:00:00:00:01-00",
            },
        },
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(
            hass,
            aioclient_mock,
            options={CONF_ALLOW_DECONZ_GROUPS: False},
        )

    assert len(hass.states.async_all()) == 1
    assert hass.states.get("light.tunable_white_light")
    assert not hass.states.get("light.light_group")
    assert not hass.states.get("light.empty_group")

    hass.config_entries.async_update_entry(
        config_entry, options={CONF_ALLOW_DECONZ_GROUPS: True}
    )
    await hass.async_block_till_done()

    assert len(hass.states.async_all()) == 2
    assert hass.states.get("light.light_group")

    hass.config_entries.async_update_entry(
        config_entry, options={CONF_ALLOW_DECONZ_GROUPS: False}
    )
    await hass.async_block_till_done()

    assert len(hass.states.async_all()) == 1
    assert not hass.states.get("light.light_group")


async def test_non_color_light_reports_color(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_deconz_websocket
) -> None:
    """Verify hs_color does not crash when a group gets updated with a bad color value.

    After calling a scene color temp light of certain manufacturers
    report color temp in color space.
    """
    data = {
        "groups": {
            "0": {
                "action": {
                    "alert": "none",
                    "bri": 127,
                    "colormode": "hs",
                    "ct": 0,
                    "effect": "none",
                    "hue": 0,
                    "on": True,
                    "sat": 127,
                    "scene": None,
                    "xy": [0, 0],
                },
                "devicemembership": [],
                "etag": "81e42cf1b47affb72fa72bc2e25ba8bf",
                "lights": ["0", "1"],
                "name": "Group",
                "scenes": [],
                "state": {"all_on": False, "any_on": True},
                "type": "LightGroup",
            }
        },
        "lights": {
            "0": {
                "ctmax": 500,
                "ctmin": 153,
                "etag": "026bcfe544ad76c7534e5ca8ed39047c",
                "hascolor": True,
                "manufacturername": "dresden elektronik",
                "modelid": "FLS-PP3",
                "name": "Light 1",
                "pointsymbol": {},
                "state": {
                    "alert": None,
                    "bri": 111,
                    "colormode": "ct",
                    "ct": 307,
                    "effect": None,
                    "hascolor": True,
                    "hue": 7998,
                    "on": False,
                    "reachable": True,
                    "sat": 172,
                    "xy": [0.421253, 0.39921],
                },
                "swversion": "020C.201000A0",
                "type": "Extended color light",
                "uniqueid": "00:21:2E:FF:FF:EE:DD:CC-0A",
            },
            "1": {
                "colorcapabilities": 0,
                "ctmax": 65535,
                "ctmin": 0,
                "etag": "9dd510cd474791481f189d2a68a3c7f1",
                "hascolor": True,
                "lastannounced": "2020-12-17T17:44:38Z",
                "lastseen": "2021-01-11T18:36Z",
                "manufacturername": "IKEA of Sweden",
                "modelid": "TRADFRI bulb E27 WS opal 1000lm",
                "name": "Küchenlicht",
                "state": {
                    "alert": "none",
                    "bri": 156,
                    "colormode": "ct",
                    "ct": 250,
                    "on": True,
                    "reachable": True,
                },
                "swversion": "2.0.022",
                "type": "Color temperature light",
                "uniqueid": "ec:1b:bd:ff:fe:ee:ed:dd-01",
            },
        },
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        await setup_deconz_integration(hass, aioclient_mock)

    assert len(hass.states.async_all()) == 3
    assert hass.states.get("light.group").attributes[ATTR_COLOR_TEMP] == 250

    # Updating a scene will return a faulty color value for a non-color light causing an exception in hs_color
    event_changed_light = {
        "e": "changed",
        "id": "1",
        "r": "lights",
        "state": {
            "alert": None,
            "bri": 216,
            "colormode": "xy",
            "ct": 410,
            "on": True,
            "reachable": True,
        },
        "t": "event",
        "uniqueid": "ec:1b:bd:ff:fe:ee:ed:dd-01",
    }
    await mock_deconz_websocket(data=event_changed_light)
    await hass.async_block_till_done()

    # Bug is fixed if we reach this point, but device won't have neither color temp nor color
    with pytest.raises(KeyError):
        assert hass.states.get("light.group").attributes[ATTR_COLOR_TEMP]
        assert hass.states.get("light.group").attributes[ATTR_HS_COLOR]


async def test_verify_group_supported_features(
    hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
    """Test that group supported features reflect what included lights support."""
    data = {
        "groups": {
            "1": {
                "id": "Group1",
                "name": "Group",
                "type": "LightGroup",
                "state": {"all_on": False, "any_on": True},
                "action": {},
                "scenes": [],
                "lights": ["1", "2", "3"],
            },
        },
        "lights": {
            "1": {
                "name": "Dimmable light",
                "state": {"on": True, "bri": 255, "reachable": True},
                "type": "Light",
                "uniqueid": "00:00:00:00:00:00:00:01-00",
            },
            "2": {
                "name": "Color light",
                "state": {
                    "on": True,
                    "bri": 100,
                    "colormode": "xy",
                    "effect": "colorloop",
                    "xy": (500, 500),
                    "reachable": True,
                },
                "type": "Extended color light",
                "uniqueid": "00:00:00:00:00:00:00:02-00",
            },
            "3": {
                "ctmax": 454,
                "ctmin": 155,
                "name": "Tunable light",
                "state": {"on": True, "colormode": "ct", "ct": 2500, "reachable": True},
                "type": "Tunable white light",
                "uniqueid": "00:00:00:00:00:00:00:03-00",
            },
        },
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        await setup_deconz_integration(hass, aioclient_mock)

    assert len(hass.states.async_all()) == 4

    assert hass.states.get("light.group").state == STATE_ON
    assert (
        hass.states.get("light.group").attributes[ATTR_SUPPORTED_FEATURES]
        == LightEntityFeature.TRANSITION
        | LightEntityFeature.FLASH
        | LightEntityFeature.EFFECT
    )