"""The tests for the water_heater platform of evohome.

Not all evohome systems will have a DHW zone.
"""

from unittest.mock import patch

from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.components.water_heater import (
    ATTR_AWAY_MODE,
    ATTR_OPERATION_MODE,
    DOMAIN as WATER_HEATER_DOMAIN,
    SERVICE_SET_AWAY_MODE,
    SERVICE_SET_OPERATION_MODE,
)
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON
from homeassistant.core import HomeAssistant

from .conftest import setup_evohome
from .const import TEST_INSTALLS_WITH_DHW


@pytest.mark.parametrize("install", TEST_INSTALLS_WITH_DHW)
async def test_setup_platform(
    hass: HomeAssistant,
    config: dict[str, str],
    install: str,
    snapshot: SnapshotAssertion,
    freezer: FrozenDateTimeFactory,
) -> None:
    """Test entities and their states after setup of evohome."""

    # Cannot use the evohome fixture, as need to set dtm first
    #  - some extended state attrs are relative the current time
    freezer.move_to("2024-07-10T12:00:00Z")

    async for _ in setup_evohome(hass, config, install=install):
        pass

    water_heater_states = hass.states.async_all(WATER_HEATER_DOMAIN)
    assert water_heater_states

    for x in water_heater_states:
        assert x == snapshot(name=f"{x.entity_id}-state")


@pytest.mark.parametrize("install", TEST_INSTALLS_WITH_DHW)
async def test_set_operation_mode(
    hass: HomeAssistant,
    dhw_id: str,
    freezer: FrozenDateTimeFactory,
    snapshot: SnapshotAssertion,
) -> None:
    """Test SERVICE_SET_OPERATION_MODE of an evohome DHW zone."""

    freezer.move_to("2024-07-10T11:55:00Z")
    results = []

    # SERVICE_SET_OPERATION_MODE: auto
    with patch("evohomeasync2.hotwater.HotWater.reset") as mock_fcn:
        await hass.services.async_call(
            WATER_HEATER_DOMAIN,
            SERVICE_SET_OPERATION_MODE,
            {
                ATTR_ENTITY_ID: dhw_id,
                ATTR_OPERATION_MODE: "auto",
            },
            blocking=True,
        )

        mock_fcn.assert_awaited_once_with()

    # SERVICE_SET_OPERATION_MODE: off (until next scheduled setpoint)
    with patch("evohomeasync2.hotwater.HotWater.set_off") as mock_fcn:
        await hass.services.async_call(
            WATER_HEATER_DOMAIN,
            SERVICE_SET_OPERATION_MODE,
            {
                ATTR_ENTITY_ID: dhw_id,
                ATTR_OPERATION_MODE: "off",
            },
            blocking=True,
        )

        mock_fcn.assert_awaited_once()

        assert mock_fcn.await_args is not None  # mypy hint
        assert mock_fcn.await_args.args == ()
        assert mock_fcn.await_args.kwargs != {}

        results.append(mock_fcn.await_args.kwargs)

    # SERVICE_SET_OPERATION_MODE: on (until next scheduled setpoint)
    with patch("evohomeasync2.hotwater.HotWater.set_on") as mock_fcn:
        await hass.services.async_call(
            WATER_HEATER_DOMAIN,
            SERVICE_SET_OPERATION_MODE,
            {
                ATTR_ENTITY_ID: dhw_id,
                ATTR_OPERATION_MODE: "on",
            },
            blocking=True,
        )

        mock_fcn.assert_awaited_once()

        assert mock_fcn.await_args is not None  # mypy hint
        assert mock_fcn.await_args.args == ()
        assert mock_fcn.await_args.kwargs != {}

        results.append(mock_fcn.await_args.kwargs)

    assert results == snapshot


@pytest.mark.parametrize("install", TEST_INSTALLS_WITH_DHW)
async def test_set_away_mode(hass: HomeAssistant, dhw_id: str) -> None:
    """Test SERVICE_SET_AWAY_MODE of an evohome DHW zone."""

    # set_away_mode: off
    with patch("evohomeasync2.hotwater.HotWater.reset") as mock_fcn:
        await hass.services.async_call(
            WATER_HEATER_DOMAIN,
            SERVICE_SET_AWAY_MODE,
            {
                ATTR_ENTITY_ID: dhw_id,
                ATTR_AWAY_MODE: "off",
            },
            blocking=True,
        )

        mock_fcn.assert_awaited_once_with()

    # set_away_mode: on
    with patch("evohomeasync2.hotwater.HotWater.set_off") as mock_fcn:
        await hass.services.async_call(
            WATER_HEATER_DOMAIN,
            SERVICE_SET_AWAY_MODE,
            {
                ATTR_ENTITY_ID: dhw_id,
                ATTR_AWAY_MODE: "on",
            },
            blocking=True,
        )

        mock_fcn.assert_awaited_once_with()


@pytest.mark.parametrize("install", TEST_INSTALLS_WITH_DHW)
async def test_turn_off(hass: HomeAssistant, dhw_id: str) -> None:
    """Test SERVICE_TURN_OFF of an evohome DHW zone."""

    # turn_off
    with patch("evohomeasync2.hotwater.HotWater.set_off") as mock_fcn:
        await hass.services.async_call(
            WATER_HEATER_DOMAIN,
            SERVICE_TURN_OFF,
            {
                ATTR_ENTITY_ID: dhw_id,
            },
            blocking=True,
        )

        mock_fcn.assert_awaited_once_with()


@pytest.mark.parametrize("install", TEST_INSTALLS_WITH_DHW)
async def test_turn_on(hass: HomeAssistant, dhw_id: str) -> None:
    """Test SERVICE_TURN_ON of an evohome DHW zone."""

    # turn_on
    with patch("evohomeasync2.hotwater.HotWater.set_on") as mock_fcn:
        await hass.services.async_call(
            WATER_HEATER_DOMAIN,
            SERVICE_TURN_ON,
            {
                ATTR_ENTITY_ID: dhw_id,
            },
            blocking=True,
        )

        mock_fcn.assert_awaited_once_with()
