"""Valve for Shelly."""
from __future__ import annotations

from dataclasses import dataclass
from typing import Any, cast

from aioshelly.block_device import Block
from aioshelly.const import BLOCK_GENERATIONS, MODEL_GAS

from homeassistant.components.valve import (
    ValveDeviceClass,
    ValveEntity,
    ValveEntityDescription,
    ValveEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .coordinator import ShellyBlockCoordinator, get_entry_data
from .entity import (
    BlockEntityDescription,
    ShellyBlockAttributeEntity,
    async_setup_block_attribute_entities,
)
from .utils import get_device_entry_gen


@dataclass(kw_only=True, frozen=True)
class BlockValveDescription(BlockEntityDescription, ValveEntityDescription):
    """Class to describe a BLOCK valve."""


GAS_VALVE = BlockValveDescription(
    key="valve|valve",
    name="Valve",
    available=lambda block: block.valve not in ("failure", "checking"),
    removal_condition=lambda _, block: block.valve in ("not_connected", "unknown"),
)


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up valves for device."""
    if get_device_entry_gen(config_entry) in BLOCK_GENERATIONS:
        async_setup_block_entry(hass, config_entry, async_add_entities)


@callback
def async_setup_block_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up valve for device."""
    coordinator = get_entry_data(hass)[config_entry.entry_id].block
    assert coordinator and coordinator.device.blocks

    if coordinator.model == MODEL_GAS:
        async_setup_block_attribute_entities(
            hass,
            async_add_entities,
            coordinator,
            {("valve", "valve"): GAS_VALVE},
            BlockShellyValve,
        )


class BlockShellyValve(ShellyBlockAttributeEntity, ValveEntity):
    """Entity that controls a valve on block based Shelly devices."""

    entity_description: BlockValveDescription
    _attr_device_class = ValveDeviceClass.GAS
    _attr_supported_features = ValveEntityFeature.OPEN | ValveEntityFeature.CLOSE

    def __init__(
        self,
        coordinator: ShellyBlockCoordinator,
        block: Block,
        attribute: str,
        description: BlockValveDescription,
    ) -> None:
        """Initialize block valve."""
        super().__init__(coordinator, block, attribute, description)
        self.control_result: dict[str, Any] | None = None
        self._attr_is_closed = bool(self.attribute_value == "closed")

    @property
    def is_closing(self) -> bool:
        """Return if the valve is closing."""
        if self.control_result:
            return cast(bool, self.control_result["state"] == "closing")

        return self.attribute_value == "closing"

    @property
    def is_opening(self) -> bool:
        """Return if the valve is opening."""
        if self.control_result:
            return cast(bool, self.control_result["state"] == "opening")

        return self.attribute_value == "opening"

    async def async_open_valve(self, **kwargs: Any) -> None:
        """Open valve."""
        self.control_result = await self.set_state(go="open")
        self.async_write_ha_state()

    async def async_close_valve(self, **kwargs: Any) -> None:
        """Close valve."""
        self.control_result = await self.set_state(go="close")
        self.async_write_ha_state()

    @callback
    def _update_callback(self) -> None:
        """When device updates, clear control result that overrides state."""
        self.control_result = None
        self._attr_is_closed = bool(self.attribute_value == "closed")
        super()._update_callback()