"""Support for viewing the camera feed from a DoorBird video doorbell."""
from __future__ import annotations

import asyncio
import datetime
import logging

import aiohttp
import async_timeout

from homeassistant.components.camera import SUPPORT_STREAM, Camera
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.util.dt as dt_util

from .const import (
    DOMAIN,
    DOOR_STATION,
    DOOR_STATION_EVENT_ENTITY_IDS,
    DOOR_STATION_INFO,
)
from .entity import DoorBirdEntity

_LAST_VISITOR_INTERVAL = datetime.timedelta(minutes=2)
_LAST_MOTION_INTERVAL = datetime.timedelta(seconds=30)
_LIVE_INTERVAL = datetime.timedelta(seconds=45)
_LOGGER = logging.getLogger(__name__)
_TIMEOUT = 15  # seconds


async def async_setup_entry(hass, config_entry, async_add_entities):
    """Set up the DoorBird camera platform."""
    config_entry_id = config_entry.entry_id
    config_data = hass.data[DOMAIN][config_entry_id]
    doorstation = config_data[DOOR_STATION]
    doorstation_info = config_data[DOOR_STATION_INFO]
    device = doorstation.device

    async_add_entities(
        [
            DoorBirdCamera(
                doorstation,
                doorstation_info,
                device.live_image_url,
                "live",
                f"{doorstation.name} Live",
                doorstation.doorstation_events,
                _LIVE_INTERVAL,
                device.rtsp_live_video_url,
            ),
            DoorBirdCamera(
                doorstation,
                doorstation_info,
                device.history_image_url(1, "doorbell"),
                "last_ring",
                f"{doorstation.name} Last Ring",
                [],
                _LAST_VISITOR_INTERVAL,
            ),
            DoorBirdCamera(
                doorstation,
                doorstation_info,
                device.history_image_url(1, "motionsensor"),
                "last_motion",
                f"{doorstation.name} Last Motion",
                [],
                _LAST_MOTION_INTERVAL,
            ),
        ]
    )


class DoorBirdCamera(DoorBirdEntity, Camera):
    """The camera on a DoorBird device."""

    def __init__(
        self,
        doorstation,
        doorstation_info,
        url,
        camera_id,
        name,
        doorstation_events,
        interval=None,
        stream_url=None,
    ):
        """Initialize the camera on a DoorBird device."""
        super().__init__(doorstation, doorstation_info)
        self._url = url
        self._stream_url = stream_url
        self._name = name
        self._last_image = None
        self._supported_features = SUPPORT_STREAM if self._stream_url else 0
        self._interval = interval or datetime.timedelta
        self._last_update = datetime.datetime.min
        self._unique_id = f"{self._mac_addr}_{camera_id}"
        self._doorstation_events = doorstation_events

    async def stream_source(self):
        """Return the stream source."""
        return self._stream_url

    @property
    def unique_id(self):
        """Camera Unique id."""
        return self._unique_id

    @property
    def supported_features(self):
        """Return supported features."""
        return self._supported_features

    @property
    def name(self):
        """Get the name of the camera."""
        return self._name

    async def async_camera_image(
        self, width: int | None = None, height: int | None = None
    ) -> bytes | None:
        """Pull a still image from the camera."""
        now = dt_util.utcnow()

        if self._last_image and now - self._last_update < self._interval:
            return self._last_image

        try:
            websession = async_get_clientsession(self.hass)
            with async_timeout.timeout(_TIMEOUT):
                response = await websession.get(self._url)

            self._last_image = await response.read()
            self._last_update = now
            return self._last_image
        except asyncio.TimeoutError:
            _LOGGER.error("DoorBird %s: Camera image timed out", self._name)
            return self._last_image
        except aiohttp.ClientError as error:
            _LOGGER.error(
                "DoorBird %s: Error getting camera image: %s", self._name, error
            )
            return self._last_image

    async def async_added_to_hass(self):
        """Add callback after being added to hass.

        Registers entity_id map for the logbook
        """
        event_to_entity_id = self.hass.data[DOMAIN].setdefault(
            DOOR_STATION_EVENT_ENTITY_IDS, {}
        )
        for event in self._doorstation_events:
            event_to_entity_id[event] = self.entity_id

    async def will_remove_from_hass(self):
        """Unregister entity_id map for the logbook."""
        event_to_entity_id = self.hass.data[DOMAIN][DOOR_STATION_EVENT_ENTITY_IDS]
        for event in self._doorstation_events:
            if event in event_to_entity_id:
                del event_to_entity_id[event]
