"""Provides the Canary DataUpdateCoordinator."""

import asyncio
from collections.abc import ValuesView
from datetime import timedelta
import logging
from typing import override

from canary.api import Api
from canary.model import Location, Reading
from requests.exceptions import ConnectTimeout, HTTPError

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import DOMAIN
from .model import CanaryData

_LOGGER = logging.getLogger(__name__)


type CanaryConfigEntry = ConfigEntry[CanaryDataUpdateCoordinator]


class CanaryDataUpdateCoordinator(DataUpdateCoordinator[CanaryData]):
    """Class to manage fetching Canary data."""

    def __init__(
        self, hass: HomeAssistant, config_entry: CanaryConfigEntry, *, api: Api
    ) -> None:
        """Initialize global Canary data updater."""
        self.canary = api
        update_interval = timedelta(seconds=30)

        super().__init__(
            hass,
            _LOGGER,
            config_entry=config_entry,
            name=DOMAIN,
            update_interval=update_interval,
        )

    def _update_data(self) -> CanaryData:
        """Fetch data from Canary via sync functions."""
        locations_by_id: dict[str, Location] = {}
        readings_by_device_id: dict[str, ValuesView[Reading]] = {}

        for location in self.canary.get_locations():
            location_id = location.location_id
            locations_by_id[location_id] = location

            for device in location.devices:
                if device.is_online:
                    readings_by_device_id[device.device_id] = (
                        self.canary.get_latest_readings(device.device_id)
                    )

        return {
            "locations": locations_by_id,
            "readings": readings_by_device_id,
        }

    @override
    async def _async_update_data(self) -> CanaryData:
        """Fetch data from Canary."""

        try:
            async with asyncio.timeout(15):
                return await self.hass.async_add_executor_job(self._update_data)
        except (ConnectTimeout, HTTPError) as error:
            raise UpdateFailed(f"Invalid response from API: {error}") from error
