"""Class representing a Sonos household storage helper."""
from __future__ import annotations

import asyncio
from collections.abc import Callable, Coroutine
import logging

from soco import SoCo

from homeassistant.core import HomeAssistant
from homeassistant.helpers.debounce import Debouncer

from .const import DATA_SONOS
from .exception import SonosUpdateError

_LOGGER = logging.getLogger(__name__)


class SonosHouseholdCoordinator:
    """Base class for Sonos household-level storage."""

    def __init__(self, hass: HomeAssistant, household_id: str) -> None:
        """Initialize the data."""
        self.hass = hass
        self.household_id = household_id
        self.async_poll: Callable[[], Coroutine[None, None, None]] | None = None
        self.last_processed_event_id: int | None = None
        self.cache_update_lock: asyncio.Lock | None = None

    def setup(self, soco: SoCo) -> None:
        """Set up the SonosAlarm instance."""
        self.update_cache(soco)
        self.hass.add_job(self._async_setup)

    async def _async_setup(self) -> None:
        """Finish setup in async context."""
        self.cache_update_lock = asyncio.Lock()
        self.async_poll = Debouncer(
            self.hass,
            _LOGGER,
            cooldown=3,
            immediate=False,
            function=self._async_poll,
        ).async_call

    @property
    def class_type(self) -> str:
        """Return the class type of this instance."""
        return type(self).__name__

    async def _async_poll(self) -> None:
        """Poll any known speaker."""
        discovered = self.hass.data[DATA_SONOS].discovered

        for uid, speaker in discovered.items():
            _LOGGER.debug("Polling %s using %s", self.class_type, speaker.soco)
            try:
                await self.async_update_entities(speaker.soco)
            except SonosUpdateError as err:
                _LOGGER.error(
                    "Could not refresh %s: %s",
                    self.class_type,
                    err,
                )
            else:
                # Prefer this SoCo instance next update
                discovered.move_to_end(uid, last=False)
                break

    async def async_update_entities(
        self, soco: SoCo, update_id: int | None = None
    ) -> None:
        """Update the cache and update entities."""
        raise NotImplementedError()

    def update_cache(self, soco: SoCo, update_id: int | None = None) -> bool:
        """Update the cache of the household-level feature and return if cache has changed."""
        raise NotImplementedError()
