"""Button platform for Enphase Envoy solar energy monitor."""

from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from typing import Any, override

from pyenphase import Envoy

from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from .const import DOMAIN
from .coordinator import EnphaseConfigEntry
from .entity import EnvoyACBAggregateControlEntity, exception_handler

PARALLEL_UPDATES = 1


@dataclass(frozen=True, kw_only=True)
class EnvoyACBButtonEntityDescription(ButtonEntityDescription):
    """Describes an Envoy ACB battery button entity."""

    press_fn: Callable[
        [Envoy, list[str], int, int], Coroutine[Any, Any, dict[str, Any]]
    ]


ACB_BUTTONS = (
    EnvoyACBButtonEntityDescription(
        key="acb_sleep",
        translation_key="acb_sleep",
        press_fn=lambda envoy, serials, low, high: envoy.set_acb_sleep(
            [
                {"serial_num": serial, "sleep_min_soc": low, "sleep_max_soc": high}
                for serial in serials
            ]
        ),
    ),
    EnvoyACBButtonEntityDescription(
        key="acb_wake",
        translation_key="acb_wake",
        press_fn=lambda envoy, serials, low, high: envoy.clear_acb_sleep(serials),
    ),
)


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: EnphaseConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up envoy button platform."""
    coordinator = config_entry.runtime_data
    envoy_data = coordinator.envoy.data
    assert envoy_data is not None
    if not envoy_data.acb_inventory:
        return

    entities: list[ButtonEntity] = [
        EnvoyACBButtonEntity(coordinator, description) for description in ACB_BUTTONS
    ]
    async_add_entities(entities)


class EnvoyACBButtonEntity(EnvoyACBAggregateControlEntity, ButtonEntity):
    """Envoy button that puts all ACB batteries to sleep or wakes them."""

    entity_description: EnvoyACBButtonEntityDescription

    @exception_handler
    @override
    async def async_press(self) -> None:
        """Send the sleep or wake request for all ACB batteries."""
        acb_inventory = self.data.acb_inventory
        assert acb_inventory is not None
        low, high = self.coordinator.acb_sleep_soc()
        try:
            await self.entity_description.press_fn(
                self.coordinator.envoy, list(acb_inventory), low, high
            )
        except ValueError as err:
            # pyenphase raises ValueError for validation failures and Envoy
            # HTTP 400 responses, which exception_handler does not cover.
            raise HomeAssistantError(
                translation_domain=DOMAIN,
                translation_key="action_error",
                translation_placeholders={
                    "host": self.coordinator.envoy.host,
                    "args": err.args[0] if err.args else str(err),
                    "action": "async_press",
                    "entity": self.entity_id,
                },
            ) from err
        await self.coordinator.async_request_refresh()
