"""Support for Watergate sensors."""

from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime, timedelta
from enum import StrEnum
import logging
from typing import override

from homeassistant.components.sensor import (
    HomeAssistant,
    SensorDeviceClass,
    SensorEntity,
    SensorEntityDescription,
    SensorStateClass,
)
from homeassistant.const import (
    SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
    EntityCategory,
    UnitOfPressure,
    UnitOfTemperature,
    UnitOfTime,
    UnitOfVolume,
    UnitOfVolumeFlowRate,
)
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.util import dt as dt_util

from .coordinator import (
    WatergateAgregatedRequests,
    WatergateConfigEntry,
    WatergateDataCoordinator,
)
from .entity import WatergateEntity

_LOGGER = logging.getLogger(__name__)

PARALLEL_UPDATES = 0


class PowerSupplyMode(StrEnum):
    """LED bar mode."""

    BATTERY = "battery"
    EXTERNAL = "external"
    BATTERY_EXTERNAL = "battery_external"


@dataclass(kw_only=True, frozen=True)
class WatergateSensorEntityDescription(SensorEntityDescription):
    """Description for Watergate sensor entities."""

    value_fn: Callable[
        [WatergateAgregatedRequests],
        StateType | datetime | PowerSupplyMode,
    ]


DESCRIPTIONS: list[WatergateSensorEntityDescription] = [
    WatergateSensorEntityDescription(
        value_fn=lambda data: (
            data.state.water_meter.volume
            if data.state and data.state.water_meter
            else None
        ),
        translation_key="water_meter_volume",
        key="water_meter_volume",
        native_unit_of_measurement=UnitOfVolume.LITERS,
        device_class=SensorDeviceClass.WATER,
        state_class=SensorStateClass.TOTAL_INCREASING,
    ),
    WatergateSensorEntityDescription(
        value_fn=lambda data: (
            data.state.water_meter.duration
            if data.state and data.state.water_meter
            else None
        ),
        translation_key="water_meter_duration",
        key="water_meter_duration",
        native_unit_of_measurement=UnitOfTime.MINUTES,
        device_class=SensorDeviceClass.DURATION,
        state_class=SensorStateClass.TOTAL_INCREASING,
    ),
    WatergateSensorEntityDescription(
        value_fn=lambda data: data.networking.rssi if data.networking else None,
        key="rssi",
        entity_category=EntityCategory.DIAGNOSTIC,
        entity_registry_enabled_default=False,
        native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
        device_class=SensorDeviceClass.SIGNAL_STRENGTH,
        state_class=SensorStateClass.MEASUREMENT,
    ),
    WatergateSensorEntityDescription(
        value_fn=lambda data: (
            dt_util.as_utc(
                dt_util.now() - timedelta(milliseconds=data.networking.wifi_uptime)
            )
            if data.networking
            else None
        ),
        translation_key="wifi_up_since",
        key="wifi_up_since",
        entity_category=EntityCategory.DIAGNOSTIC,
        entity_registry_enabled_default=False,
        device_class=SensorDeviceClass.TIMESTAMP,
    ),
    WatergateSensorEntityDescription(
        value_fn=lambda data: (
            dt_util.as_utc(
                dt_util.now() - timedelta(milliseconds=data.networking.mqtt_uptime)
            )
            if data.networking
            else None
        ),
        translation_key="mqtt_up_since",
        key="mqtt_up_since",
        entity_category=EntityCategory.DIAGNOSTIC,
        entity_registry_enabled_default=False,
        device_class=SensorDeviceClass.TIMESTAMP,
    ),
    WatergateSensorEntityDescription(
        value_fn=lambda data: (
            data.telemetry.water_temperature if data.telemetry else None
        ),
        translation_key="water_temperature",
        key="water_temperature",
        native_unit_of_measurement=UnitOfTemperature.CELSIUS,
        device_class=SensorDeviceClass.TEMPERATURE,
        state_class=SensorStateClass.MEASUREMENT,
    ),
    WatergateSensorEntityDescription(
        value_fn=lambda data: data.telemetry.pressure if data.telemetry else None,
        translation_key="water_pressure",
        key="water_pressure",
        native_unit_of_measurement=UnitOfPressure.MBAR,
        device_class=SensorDeviceClass.PRESSURE,
        state_class=SensorStateClass.MEASUREMENT,
    ),
    WatergateSensorEntityDescription(
        value_fn=lambda data: (
            data.telemetry.flow / 1000
            if data.telemetry and data.telemetry.flow is not None
            else None
        ),
        key="water_flow_rate",
        native_unit_of_measurement=UnitOfVolumeFlowRate.LITERS_PER_MINUTE,
        device_class=SensorDeviceClass.VOLUME_FLOW_RATE,
        state_class=SensorStateClass.MEASUREMENT,
    ),
    WatergateSensorEntityDescription(
        value_fn=lambda data: (
            dt_util.as_utc(dt_util.now() - timedelta(seconds=data.state.uptime))
            if data.state
            else None
        ),
        translation_key="up_since",
        key="up_since",
        entity_category=EntityCategory.DIAGNOSTIC,
        entity_registry_enabled_default=False,
        device_class=SensorDeviceClass.TIMESTAMP,
    ),
    WatergateSensorEntityDescription(
        value_fn=lambda data: (
            PowerSupplyMode(
                data.state.power_supply.replace("+", "_").replace(
                    "external_battery", "battery_external"
                )
            )
            if data.state
            else None
        ),
        translation_key="power_supply_mode",
        key="power_supply_mode",
        entity_category=EntityCategory.DIAGNOSTIC,
        entity_registry_enabled_default=False,
        device_class=SensorDeviceClass.ENUM,
        options=[member.value for member in PowerSupplyMode],
    ),
]


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: WatergateConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up all entries for Watergate Platform."""

    coordinator = config_entry.runtime_data

    async_add_entities(
        SonicSensor(coordinator, description) for description in DESCRIPTIONS
    )


class SonicSensor(WatergateEntity, SensorEntity):
    """Define a Sonic Sensor entity."""

    entity_description: WatergateSensorEntityDescription

    def __init__(
        self,
        coordinator: WatergateDataCoordinator,
        entity_description: WatergateSensorEntityDescription,
    ) -> None:
        """Initialize the sensor."""
        super().__init__(coordinator, entity_description.key)
        self.entity_description = entity_description

    @property
    @override
    def available(self) -> bool:
        """Return True if entity is available."""
        return (
            super().available
            and self.entity_description.value_fn(self.coordinator.data) is not None
        )

    @property
    @override
    def native_value(self) -> str | int | float | datetime | PowerSupplyMode | None:
        """Return the state of the sensor."""
        return self.entity_description.value_fn(self.coordinator.data)
