"""Coordinator for lookin devices."""
from __future__ import annotations

from collections.abc import Awaitable, Callable
from datetime import timedelta
import logging
import time
from typing import cast

from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

_LOGGER = logging.getLogger(__name__)

NEVER_TIME = -120.0  # Time that will never match time.monotonic()
ACTIVE_UPDATES_INTERVAL = 3  # Consider active for 3x the update interval


class LookinPushCoordinator:
    """Keep track of when the last push update was."""

    def __init__(self, name: str) -> None:
        """Init the push coordininator."""
        self.last_update = NEVER_TIME
        self.name = name

    def update(self) -> None:
        """Remember the last push time."""
        self.last_update = time.monotonic()

    def active(self, interval: timedelta) -> bool:
        """Check if the last push update was recently."""
        time_since_last_update = time.monotonic() - self.last_update
        is_active = (
            time_since_last_update < interval.total_seconds() * ACTIVE_UPDATES_INTERVAL
        )
        _LOGGER.debug(
            "%s: push updates active: %s (time_since_last_update=%s)",
            self.name,
            is_active,
            time_since_last_update,
        )
        return is_active


class LookinDataUpdateCoordinator(DataUpdateCoordinator):
    """DataUpdateCoordinator to gather data for a specific lookin devices."""

    def __init__(
        self,
        hass: HomeAssistant,
        push_coordinator: LookinPushCoordinator,
        name: str,
        update_interval: timedelta | None = None,
        update_method: Callable[[], Awaitable[dict]] | None = None,
    ) -> None:
        """Initialize DataUpdateCoordinator to gather data for specific device."""
        self.push_coordinator = push_coordinator
        super().__init__(
            hass,
            _LOGGER,
            name=name,
            update_interval=update_interval,
            update_method=update_method,
        )

    @callback
    def async_set_updated_data(self, data: dict) -> None:
        """Manually update data, notify listeners and reset refresh interval, and remember."""
        self.push_coordinator.update()
        super().async_set_updated_data(data)

    async def _async_update_data(self) -> dict:
        """Fetch data only if we have not received a push inside the interval."""
        interval = self.update_interval
        if (
            interval is not None
            and self.last_update_success
            and self.data
            and self.push_coordinator.active(interval)
        ):
            data = self.data
        else:
            data = await super()._async_update_data()
        return cast(dict, data)
