"""Platform for button integration."""

from collections.abc import Callable
import logging
from typing import Any

from aiohttp.client_exceptions import ClientConnectionError
from wyzeapy import Wyzeapy
from wyzeapy.services.irrigation_service import Irrigation, IrrigationService, Zone
from wyzeapy.services.switch_service import Switch

from homeassistant.components.button import ButtonDeviceClass, ButtonEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_registry import EntityCategory

from .const import CONF_CLIENT, DOMAIN, RESET_BUTTON_PRESSED
from .token_manager import token_exception_handler

_LOGGER = logging.getLogger(__name__)
ATTRIBUTION = "Data provided by Wyze"
OUTDOOR_PLUGS = ["WLPPO"]


@token_exception_handler
async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: Callable[[list[Any], bool], None],
) -> None:
    """This function sets up the config entry.

    :param hass: The Home Assistant Instance
    :param config_entry: The current config entry
    :param async_add_entities: This function adds entities to the config entry
    :return:
    """

    _LOGGER.debug("""Creating new Wyze button component""")
    client: Wyzeapy = hass.data[DOMAIN][config_entry.entry_id][CONF_CLIENT]
    irrigation_service = await client.irrigation_service
    switch_service = await client.switch_service

    # Get all irrigation devices
    irrigation_devices = await irrigation_service.get_irrigations()

    # Create a button entity for each zone in each irrigation device
    buttons = []
    for device in irrigation_devices:
        # Update the device to get its zones
        device = await irrigation_service.update(device)
        # Add a button entity for each enabled zone in the irrigation device
        buttons.extend(
            [
                WyzeIrrigationZoneButton(irrigation_service, device, zone)
                for zone in device.zones
                if zone.enabled
            ]
        )
        # Add a stop all schedules button for each irrigation device, not each zone
        buttons.append(WyzeIrrigationStopAllButton(irrigation_service, device))

    plugs = await switch_service.get_switches()
    buttons.extend(
        [
            WyzePowerSensorResetButton(plug)
            for plug in plugs
            if plug.product_model in OUTDOOR_PLUGS
        ]
    )

    async_add_entities(buttons, True)


class WyzeIrrigationZoneButton(ButtonEntity):
    """Representation of a Wyze Irrigation Zone Button."""

    _attr_has_entity_name = True

    def __init__(
        self, irrigation_service: IrrigationService, irrigation: Irrigation, zone: Zone
    ) -> None:
        """Initialize the irrigation zone button."""
        self._irrigation_service = irrigation_service
        self._device = irrigation
        self._zone = zone

    @property
    def name(self) -> str:
        """Return the name of the zone."""
        return f"{self._zone.name}"

    @property
    def unique_id(self) -> str:
        """Return a unique ID for the zone."""
        return f"Start {self._device.mac}-zone-{self._zone.zone_number}"

    @property
    def device_info(self) -> DeviceInfo:
        """Return device information about this entity."""
        return DeviceInfo(
            identifiers={(DOMAIN, self._device.mac)},
            name=self._device.nickname,
            manufacturer="WyzeLabs",
            model=self._device.product_model,
            connections={(dr.CONNECTION_NETWORK_MAC, self._device.mac)},
        )

    @property
    def device_class(self) -> str:
        """Return the device class of the button."""
        return ButtonDeviceClass.RESTART

    @property
    def icon(self) -> str:
        """Return the icon for the zone start button."""
        return "mdi:sprinkler"

    @property
    def extra_state_attributes(self) -> dict[str, Any]:
        """Return entity specific state attributes."""
        return {
            "zone_number": self._zone.zone_number,
            "zone_id": self._zone.zone_id,
            "enabled": self._zone.enabled,
            "quickrun_duration": self._zone.quickrun_duration,
        }

    async def async_press(self) -> None:
        """Start the zone with its quickrun duration.

        This method is called when the button is pressed in Home Assistant.
        It starts the irrigation zone for the duration specified in the corresponding number entity.

        The number entity is found using the exact unique_id pattern that follows the format:
        {device.mac}-zone-{zone.zone_number}-quickrun-duration

        Raises:
            HomeAssistantError: If the zone cannot be started or the number entity is invalid.
        """
        try:
            # The quickrun duration field doesnt exist in the Wyze API
            # It has been created in Home Assistant as a number entity
            # to conveniently trigger a zone start with a specific duration

            # Get the device registry and find the device
            device_registry = dr.async_get(self.hass)
            device = device_registry.async_get_device(
                identifiers={(DOMAIN, self._device.mac)}
            )
            if not device:
                raise HomeAssistantError(f"Device not found for MAC {self._device.mac}")

            # Get the entity registry
            entity_registry = er.async_get(self.hass)

            # Find the matching number entity using the zone number and device MAC
            # The number entities have unique_id pattern: {device.mac}-zone-{zone.zone_number}-quickrun-duration
            expected_unique_id = (
                f"{self._device.mac}-zone-{self._zone.zone_number}-quickrun-duration"
            )

            matching_entity = None
            for entity_id, entity in entity_registry.entities.items():
                if (
                    entity.device_id == device.id
                    and entity.platform == DOMAIN
                    and entity_id.startswith("number.")
                    and entity.unique_id == expected_unique_id
                ):
                    matching_entity = entity_id
                    break

            _LOGGER.debug(
                "Looking for number entity with unique_id: %s", expected_unique_id
            )
            _LOGGER.debug("Found matching entity: %s", matching_entity)

            if not matching_entity:
                raise HomeAssistantError(
                    f"No number entity found for zone {self._zone.name} (zone {self._zone.zone_number}, device: {self._device.mac})"
                )

            # Get the current state of the number entity
            state = self.hass.states.get(matching_entity)
            if state is None or state.state in ["unavailable", "unknown"]:
                raise HomeAssistantError(
                    f"Number entity {matching_entity} is unavailable or unknown"
                )

            # Convert duration from minutes to seconds
            try:
                duration_minutes = float(state.state)
                if duration_minutes <= 0:
                    raise ValueError("Duration must be greater than 0")
                duration_seconds = int(duration_minutes * 60)
            except ValueError as err:
                raise HomeAssistantError(
                    f"Invalid duration {state.state} for {matching_entity}"
                ) from err

            _LOGGER.debug(
                "Starting zone %s (zone %s) for %s minutes (%s seconds)",
                self._zone.name,
                self._zone.zone_number,
                duration_minutes,
                duration_seconds,
            )

            # Start the zone with the specified duration
            await self._irrigation_service.start_zone(
                self._device, self._zone.zone_number, duration_seconds
            )

        except HomeAssistantError as err:
            _LOGGER.error("Failed to start zone %s: %s", self._zone.name, err)
            raise
        except Exception as err:
            _LOGGER.error("Unexpected error starting zone %s: %s", self._zone.name, err)
            raise HomeAssistantError(
                f"Failed to start zone {self._zone.name}: {err}"
            ) from err


class WyzeIrrigationStopAllButton(ButtonEntity):
    """Representation of a Wyze Irrigation Stop All Schedules Button."""

    _attr_name = "Stop All Zones"

    def __init__(
        self, irrigation_service: IrrigationService, irrigation: Irrigation
    ) -> None:
        """Initialize the irrigation stop all button."""
        self._irrigation_service = irrigation_service
        self._device = irrigation

    @property
    def unique_id(self) -> str:
        """Return a unique ID for the button."""
        return f"Stop All {self._device.mac}"

    @property
    def device_info(self) -> DeviceInfo:
        """Return device information about this entity."""
        return DeviceInfo(
            identifiers={(DOMAIN, self._device.mac)},
            name=self._device.nickname,
            manufacturer="WyzeLabs",
            model=self._device.product_model,
            serial_number=self._device.sn,
            connections={(dr.CONNECTION_NETWORK_MAC, self._device.mac)},
        )

    @property
    def device_class(self) -> str:
        """Return the device class of the button."""
        return ButtonDeviceClass.RESTART

    @property
    def icon(self) -> str:
        """Return the icon for the stop all button."""
        return "mdi:octagon"

    async def async_press(self) -> None:
        """Stop all running irrigation schedules.

        This method is called when the button is pressed in Home Assistant.
        It will stop all running irrigation schedules for the device.

        Raises:
            HomeAssistantError: If the schedules cannot be stopped.
        """
        try:
            await self._irrigation_service.stop_running_schedule(self._device)
        except ClientConnectionError as err:
            raise HomeAssistantError(f"Failed to stop schedules: {err}") from err
        except Exception as err:
            _LOGGER.error("Error stopping schedules: %s", err)
            raise HomeAssistantError(f"Failed to stop schedules: {err}") from err


class WyzePowerSensorResetButton(ButtonEntity):
    """Wyze Power Sensor Reset Button."""

    _attr_has_entity_name = True
    _attr_should_poll = False
    _attr_entity_category = EntityCategory.CONFIG
    _attr_name = "Energy Usage Reset"

    def __init__(self, switch: Switch) -> None:
        """Initialize a power sensor reset button."""
        self._switch = switch

    @property
    def device_info(self) -> DeviceInfo:
        """Return device information about this entity."""
        return DeviceInfo(
            identifiers={(DOMAIN, self._switch.mac)},
            name=self._switch.nickname,
        )

    @property
    def unique_id(self) -> str:
        """Create a unique ID for the button."""
        return f"{self._switch.mac} Reset button"

    async def async_press(self) -> None:
        """Reset the sensor usage."""
        async_dispatcher_send(
            self.hass,
            f"{RESET_BUTTON_PRESSED}-{self._switch.mac}",
            self._switch,
        )
