"""AsusRouter entity module."""

from __future__ import annotations

import logging
from typing import Any

from asusrouter.modules.homeassistant import convert_to_ha_state_bool
from asusrouter.modules.state import AsusState
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import (
    CoordinatorEntity,
    DataUpdateCoordinator,
)

from .const import ASUSROUTER, COORDINATOR, DOMAIN
from .dataclass import (
    ARBinaryDescription,
    AREntityDescription,
    ARSwitchDescription,
)
from .helpers import to_unique_id
from .router import ARDevice

_LOGGER = logging.getLogger(__name__)


async def async_setup_ar_entry(  # noqa: PLR0913
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
    sensors: list[AREntityDescription],
    sensor_class: type[AREntity],
    hide: list[str] | None = None,
) -> None:
    """Set up AsusRouter entities."""

    router: ARDevice = hass.data[DOMAIN][config_entry.entry_id][ASUSROUTER]
    entities = []

    if not hide:
        hide = []

    for sensor_data in router.sensor_coordinator.values():
        coordinator = sensor_data[COORDINATOR]
        for sensor_description in sensors:
            try:
                sensor_type = sensor_description.key_group

                # Make sure extra state attributes are dict
                if not sensor_description.extra_state_attributes:
                    sensor_description.extra_state_attributes = {}

                if (
                    sensor_type in sensor_data
                    and sensor_description.key in sensor_data[sensor_type]
                ):
                    # Hide protected values
                    sensor_description.extra_state_attributes = {
                        key: value
                        for key, value in sensor_description.extra_state_attributes.items()  # noqa: E501
                        if value not in hide
                    }

                    entities.append(
                        sensor_class(coordinator, router, sensor_description)
                    )
            except Exception as ex:  # noqa: BLE001
                _LOGGER.warning(
                    "Got an exception when creating entities: %s. "
                    "Please, report this. Sensor description: %s",
                    ex,
                    sensor_description,
                )

    async_add_entities(entities)


class AREntity(CoordinatorEntity):
    """AsusRouter entity."""

    def __init__(
        self,
        coordinator: DataUpdateCoordinator,
        router: ARDevice,
        description: AREntityDescription,
    ) -> None:
        """Initialize AsusRouter entity."""

        super().__init__(coordinator)
        self.router = router
        self.api = router.bridge.api
        self.coordinator = coordinator

        self._attr_name = f"{router._conf_name} {description.name}"
        self._attr_unique_id = to_unique_id(f"{router.mac}_{description.name}")
        self._attr_device_info = router.device_info
        self._attr_capability_attributes = description.capabilities

    @property
    def extra_state_attributes(self) -> dict[str, Any]:
        """Return extra state attributes."""

        # Check if description is of the needed class
        if not isinstance(self.entity_description, AREntityDescription):
            return {}

        description = self.entity_description
        _attributes = description.extra_state_attributes
        if not _attributes:
            return {}

        # Mask attributes
        attrs_to_mask = self.router.sensor_filters.get(
            (description.key_group, description.key),
            [],
        )
        for attr in attrs_to_mask:
            if attr in _attributes:
                _attributes.pop(attr, None)

        attributes = {}

        for attr in _attributes:
            if attr in self.coordinator.data:
                attributes[_attributes[attr]] = self.coordinator.data[attr]

        return dict(sorted(attributes.items())) or {}


class ARBinaryEntity(AREntity):
    """AsusRouter binary entity."""

    def __init__(
        self,
        coordinator: DataUpdateCoordinator,
        router: ARDevice,
        description: AREntityDescription,
    ) -> None:
        """Initialize AsusRouter binary entity."""

        super().__init__(coordinator, router, description)
        if isinstance(description, ARBinaryDescription | ARSwitchDescription):
            self._icon_onoff = bool(
                description.icon_on and description.icon_off
            )

    @property
    def is_on(self) -> bool | None:
        """Get the state."""

        return convert_to_ha_state_bool(
            self.coordinator.data.get(self.entity_description.key)
        )

    @property
    def icon(self) -> str | None:
        """Get the icon."""

        if (
            isinstance(
                self.entity_description,
                ARBinaryDescription | ARSwitchDescription,
            )
            and self._icon_onoff
        ):
            if self.is_on:
                return self.entity_description.icon_on
            return self.entity_description.icon_off
        if self.entity_description.icon:
            return self.entity_description.icon
        return None

    async def _set_state(
        self,
        state: AsusState,
        expect_modify: bool = False,
        **kwargs: Any,
    ) -> None:
        """Set switch state."""
        try:
            _LOGGER.debug("Setting state to %s", state)
            result = await self.api.async_set_state(
                state=state, expect_modify=expect_modify, **kwargs
            )
            await self.coordinator.async_request_refresh()
            if not result:
                _LOGGER.debug("State was not set!")
        except Exception as ex:  # noqa: BLE001
            _LOGGER.error("Unable to set state with an exception: %s", ex)
