from __future__ import annotations

import pytest
from pytest_mock import MockerFixture

from kasa import Module
from kasa.smart import SmartDevice
from kasa.smart.modules.mop import Waterlevel

from ...device_fixtures import get_parent_and_child_modules, parametrize

mop = parametrize("has mop", component_filter="mop", protocol_filter={"SMART"})


@mop
@pytest.mark.parametrize(
    ("feature", "prop_name", "type"),
    [
        ("mop_attached", "mop_attached", bool),
        ("mop_waterlevel", "waterlevel", str),
    ],
)
async def test_features(dev: SmartDevice, feature: str, prop_name: str, type: type):
    """Test that features are registered and work as expected."""
    mod = next(get_parent_and_child_modules(dev, Module.Mop))
    assert mod is not None

    prop = getattr(mod, prop_name)
    assert isinstance(prop, type)

    feat = mod._device.features[feature]
    assert feat.value == prop
    assert isinstance(feat.value, type)


@mop
async def test_mop_waterlevel(dev: SmartDevice, mocker: MockerFixture):
    """Test dust mode."""
    mop_module = next(get_parent_and_child_modules(dev, Module.Mop))
    call = mocker.spy(mop_module, "call")

    waterlevel = mop_module._device.features["mop_waterlevel"]
    assert mop_module.waterlevel == waterlevel.value

    new_level = Waterlevel.High
    await mop_module.set_waterlevel(new_level.name)

    params = mop_module._settings.copy()
    params["cistern"] = new_level.value

    call.assert_called_with("setCleanAttr", params)

    await dev.update()

    assert mop_module.waterlevel == new_level.name

    with pytest.raises(ValueError, match="Invalid waterlevel"):
        await mop_module.set_waterlevel("invalid")