"""Image platform for UniFi Network integration.

Support for QR code for guest WLANs.
"""
from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
from typing import Generic

from aiounifi.interfaces.api_handlers import ItemEvent
from aiounifi.interfaces.wlans import Wlans
from aiounifi.models.api import ApiItemT
from aiounifi.models.wlan import Wlan

from homeassistant.components.image import ImageEntity, ImageEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.util.dt as dt_util

from .const import DOMAIN as UNIFI_DOMAIN
from .controller import UniFiController
from .entity import (
    HandlerT,
    UnifiEntity,
    UnifiEntityDescription,
    async_wlan_available_fn,
    async_wlan_device_info_fn,
)


@callback
def async_wlan_qr_code_image_fn(controller: UniFiController, wlan: Wlan) -> bytes:
    """Calculate receiving data transfer value."""
    return controller.api.wlans.generate_wlan_qr_code(wlan)


@dataclass
class UnifiImageEntityDescriptionMixin(Generic[HandlerT, ApiItemT]):
    """Validate and load entities from different UniFi handlers."""

    image_fn: Callable[[UniFiController, ApiItemT], bytes]
    value_fn: Callable[[ApiItemT], str | None]


@dataclass
class UnifiImageEntityDescription(
    ImageEntityDescription,
    UnifiEntityDescription[HandlerT, ApiItemT],
    UnifiImageEntityDescriptionMixin[HandlerT, ApiItemT],
):
    """Class describing UniFi image entity."""


ENTITY_DESCRIPTIONS: tuple[UnifiImageEntityDescription, ...] = (
    UnifiImageEntityDescription[Wlans, Wlan](
        key="WLAN QR Code",
        entity_category=EntityCategory.DIAGNOSTIC,
        has_entity_name=True,
        entity_registry_enabled_default=False,
        allowed_fn=lambda controller, obj_id: True,
        api_handler_fn=lambda api: api.wlans,
        available_fn=async_wlan_available_fn,
        device_info_fn=async_wlan_device_info_fn,
        event_is_on=None,
        event_to_subscribe=None,
        name_fn=lambda wlan: "QR Code",
        object_fn=lambda api, obj_id: api.wlans[obj_id],
        should_poll=False,
        supported_fn=lambda controller, obj_id: True,
        unique_id_fn=lambda controller, obj_id: f"qr_code-{obj_id}",
        image_fn=async_wlan_qr_code_image_fn,
        value_fn=lambda obj: obj.x_passphrase,
    ),
)


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up image platform for UniFi Network integration."""
    controller: UniFiController = hass.data[UNIFI_DOMAIN][config_entry.entry_id]

    if not controller.is_admin:
        return

    controller.register_platform_add_entities(
        UnifiImageEntity, ENTITY_DESCRIPTIONS, async_add_entities
    )


class UnifiImageEntity(UnifiEntity[HandlerT, ApiItemT], ImageEntity):
    """Base representation of a UniFi image."""

    entity_description: UnifiImageEntityDescription[HandlerT, ApiItemT]
    _attr_content_type = "image/png"

    current_image: bytes | None = None
    previous_value: str | None = None

    def __init__(
        self,
        obj_id: str,
        controller: UniFiController,
        description: UnifiEntityDescription[HandlerT, ApiItemT],
    ) -> None:
        """Initiatlize UniFi Image entity."""
        super().__init__(obj_id, controller, description)
        ImageEntity.__init__(self, controller.hass)

    def image(self) -> bytes | None:
        """Return bytes of image."""
        if self.current_image is None:
            description = self.entity_description
            obj = description.object_fn(self.controller.api, self._obj_id)
            self.current_image = description.image_fn(self.controller, obj)
        return self.current_image

    @callback
    def async_update_state(self, event: ItemEvent, obj_id: str) -> None:
        """Update entity state."""
        description = self.entity_description
        obj = description.object_fn(self.controller.api, self._obj_id)
        if (value := description.value_fn(obj)) != self.previous_value:
            self.previous_value = value
            self.current_image = None
            self._attr_image_last_updated = dt_util.utcnow()
