"""Support for powerwall binary sensors."""

from typing import TYPE_CHECKING, override

from tesla_powerwall import GridStatus, MeterType

from homeassistant.components.binary_sensor import (
    BinarySensorDeviceClass,
    BinarySensorEntity,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from .coordinator import PowerwallConfigEntry
from .entity import PowerWallEntity

CONNECTED_GRID_STATUSES = {
    GridStatus.TRANSITION_TO_GRID,
    GridStatus.CONNECTED,
}


async def async_setup_entry(
    hass: HomeAssistant,
    entry: PowerwallConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up the powerwall sensors."""
    powerwall_data = entry.runtime_data
    base_info = powerwall_data["base_info"]
    if base_info.restricted:
        # Running and Connected sensors require /api/sitemaster which 404s on PW3.
        sensor_classes: tuple[type[PowerWallEntity], ...] = (
            PowerWallGridServicesActiveSensor,
            PowerWallGridStatusSensor,
            PowerWallChargingStatusSensor,
        )
    else:
        sensor_classes = (
            PowerWallRunningSensor,
            PowerWallGridServicesActiveSensor,
            PowerWallGridStatusSensor,
            PowerWallConnectedSensor,
            PowerWallChargingStatusSensor,
        )
    async_add_entities(
        [sensor_class(powerwall_data) for sensor_class in sensor_classes]
    )


class PowerWallRunningSensor(PowerWallEntity, BinarySensorEntity):
    """Representation of an Powerwall running sensor."""

    _attr_translation_key = "status"
    _attr_device_class = BinarySensorDeviceClass.POWER

    @property
    @override
    def unique_id(self) -> str:
        """Device Uniqueid."""
        return f"{self.base_unique_id}_running"

    @property
    @override
    def is_on(self) -> bool:
        """Get the powerwall running state."""
        site_master = self.data.site_master
        if TYPE_CHECKING:
            assert site_master is not None
        return site_master.is_running


class PowerWallConnectedSensor(PowerWallEntity, BinarySensorEntity):
    """Representation of an Powerwall connected sensor."""

    _attr_translation_key = "connected_to_tesla"
    _attr_device_class = BinarySensorDeviceClass.CONNECTIVITY

    @property
    @override
    def unique_id(self) -> str:
        """Device Uniqueid."""
        return f"{self.base_unique_id}_connected_to_tesla"

    @property
    @override
    def is_on(self) -> bool:
        """Get the powerwall connected to tesla state."""
        site_master = self.data.site_master
        if TYPE_CHECKING:
            assert site_master is not None
        return site_master.is_connected_to_tesla


class PowerWallGridServicesActiveSensor(PowerWallEntity, BinarySensorEntity):
    """Representation of a Powerwall grid services active sensor."""

    _attr_translation_key = "grid_services_active"
    _attr_device_class = BinarySensorDeviceClass.POWER

    @property
    @override
    def unique_id(self) -> str:
        """Device Uniqueid."""
        return f"{self.base_unique_id}_grid_services_active"

    @property
    @override
    def is_on(self) -> bool:
        """Grid services is active."""
        return self.data.grid_services_active


class PowerWallGridStatusSensor(PowerWallEntity, BinarySensorEntity):
    """Representation of an Powerwall grid status sensor."""

    _attr_translation_key = "grid_status"
    _attr_device_class = BinarySensorDeviceClass.POWER

    @property
    @override
    def unique_id(self) -> str:
        """Device Uniqueid."""
        return f"{self.base_unique_id}_grid_status"

    @property
    @override
    def is_on(self) -> bool:
        """Grid is online."""
        return self.data.grid_status in CONNECTED_GRID_STATUSES


class PowerWallChargingStatusSensor(PowerWallEntity, BinarySensorEntity):
    """Representation of an Powerwall charging status sensor."""

    _attr_device_class = BinarySensorDeviceClass.BATTERY_CHARGING

    @property
    @override
    def available(self) -> bool:
        """Powerwall is available."""
        # Return False if no battery is installed
        return (
            super().available
            and self.data.meters.get_meter(MeterType.BATTERY) is not None
        )

    @property
    @override
    def unique_id(self) -> str:
        """Device Uniqueid."""
        return f"{self.base_unique_id}_powerwall_charging"  # pylint: disable=home-assistant-entity-unique-id-redundant-domain

    @property
    @override
    def is_on(self) -> bool:
        """Powerwall is charging."""
        meter = self.data.meters.get_meter(MeterType.BATTERY)
        # Meter cannot be None because of the available property
        if TYPE_CHECKING:
            assert meter is not None
        # is_sending_to returns true for values greater than 100 watts
        return meter.is_sending_to()
