"""Base entity for Android TV Remote."""
from __future__ import annotations

from androidtvremote2 import AndroidTVRemote, ConnectionClosed

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
from homeassistant.helpers.entity import Entity

from .const import DOMAIN


class AndroidTVRemoteBaseEntity(Entity):
    """Android TV Remote Base Entity."""

    _attr_name = None
    _attr_has_entity_name = True
    _attr_should_poll = False

    def __init__(self, api: AndroidTVRemote, config_entry: ConfigEntry) -> None:
        """Initialize the entity."""
        self._api = api
        self._host = config_entry.data[CONF_HOST]
        self._name = config_entry.data[CONF_NAME]
        self._attr_unique_id = config_entry.unique_id
        self._attr_is_on = api.is_on
        device_info = api.device_info
        assert config_entry.unique_id
        assert device_info
        self._attr_device_info = DeviceInfo(
            connections={(CONNECTION_NETWORK_MAC, config_entry.data[CONF_MAC])},
            identifiers={(DOMAIN, config_entry.unique_id)},
            name=self._name,
            manufacturer=device_info["manufacturer"],
            model=device_info["model"],
        )

    @callback
    def _is_available_updated(self, is_available: bool) -> None:
        """Update the state when the device is ready to receive commands or is unavailable."""
        self._attr_available = is_available
        self.async_write_ha_state()

    @callback
    def _is_on_updated(self, is_on: bool) -> None:
        """Update the state when device turns on or off."""
        self._attr_is_on = is_on
        self.async_write_ha_state()

    async def async_added_to_hass(self) -> None:
        """Register callbacks."""
        self._api.add_is_available_updated_callback(self._is_available_updated)
        self._api.add_is_on_updated_callback(self._is_on_updated)

    async def async_will_remove_from_hass(self) -> None:
        """Remove callbacks."""
        self._api.remove_is_available_updated_callback(self._is_available_updated)
        self._api.remove_is_on_updated_callback(self._is_on_updated)

    def _send_key_command(self, key_code: str, direction: str = "SHORT") -> None:
        """Send a key press to Android TV.

        This does not block; it buffers the data and arranges for it to be sent out asynchronously.
        """
        try:
            self._api.send_key_command(key_code, direction)
        except ConnectionClosed as exc:
            raise HomeAssistantError(
                "Connection to Android TV device is closed"
            ) from exc

    def _send_launch_app_command(self, app_link: str) -> None:
        """Launch an app on Android TV.

        This does not block; it buffers the data and arranges for it to be sent out asynchronously.
        """
        try:
            self._api.send_launch_app_command(app_link)
        except ConnectionClosed as exc:
            raise HomeAssistantError(
                "Connection to Android TV device is closed"
            ) from exc