"""Define a custom coordinator for the Weheat heatpump integration."""

from dataclasses import dataclass
from datetime import timedelta
from typing import override

from weheat.abstractions.discovery import HeatPumpDiscovery
from weheat.abstractions.heat_pump import HeatPump
from weheat.exceptions import (
    ApiException,
    BadRequestException,
    ForbiddenException,
    NotFoundException,
    ServiceException,
    UnauthorizedException,
)

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import API_URL, DOMAIN, ENERGY_UPDATE_INTERVAL, LOG_UPDATE_INTERVAL, LOGGER

type WeheatConfigEntry = ConfigEntry[list[WeheatData]]

EXCEPTIONS = (
    ServiceException,
    NotFoundException,
    ForbiddenException,
    BadRequestException,
    ApiException,
)


class HeatPumpInfo(HeatPumpDiscovery.HeatPumpInfo):
    """Heat pump info with additional properties."""

    def __init__(self, pump_info: HeatPumpDiscovery.HeatPumpInfo) -> None:
        """Initialize the HeatPump object with the provided pump information.

        Args:
            pump_info (HeatPumpDiscovery.HeatPumpInfo):
                An object containing the heat pump's discovery
                information, including:
                - uuid (str): Unique identifier for the heat pump.
                - uuid (str): Unique identifier for the heat pump.
                - device_name (str): Name of the heat pump device.
                - model (str): Model of the heat pump.
                - sn (str): Serial number of the heat pump.
                - has_dhw (bool): Indicates if the heat pump
                  has domestic hot water functionality.

        """
        super().__init__(
            pump_info.uuid,
            pump_info.device_name,
            pump_info.model,
            pump_info.sn,
            pump_info.has_dhw,
        )

    @property
    def readable_name(self) -> str | None:
        """Return the readable name of the heat pump."""
        return self.device_name or self.model

    @property
    def heatpump_id(self) -> str:
        """Return the heat pump id."""
        return self.uuid


class WeheatDataUpdateCoordinator(DataUpdateCoordinator[HeatPump]):
    """A custom coordinator for the Weheat heatpump integration."""

    config_entry: WeheatConfigEntry

    def __init__(
        self,
        hass: HomeAssistant,
        config_entry: WeheatConfigEntry,
        session: OAuth2Session,
        heat_pump: HeatPumpDiscovery.HeatPumpInfo,
        nr_of_heat_pumps: int,
    ) -> None:
        """Initialize the data coordinator."""
        super().__init__(
            hass,
            config_entry=config_entry,
            logger=LOGGER,
            name=DOMAIN,
            update_interval=timedelta(seconds=LOG_UPDATE_INTERVAL * nr_of_heat_pumps),
        )
        self._heat_pump_data = HeatPump(
            API_URL, heat_pump.uuid, async_get_clientsession(hass)
        )

        self.session = session

    @override
    async def _async_update_data(self) -> HeatPump:
        """Fetch data from the API."""
        await self.session.async_ensure_token_valid()

        try:
            await self._heat_pump_data.async_get_logs(
                self.session.token[CONF_ACCESS_TOKEN]
            )
        except UnauthorizedException as error:
            raise ConfigEntryAuthFailed from error
        except EXCEPTIONS as error:
            raise UpdateFailed(error) from error

        return self._heat_pump_data


class WeheatEnergyUpdateCoordinator(DataUpdateCoordinator[HeatPump]):
    """A custom Energy coordinator for the Weheat heatpump integration."""

    config_entry: WeheatConfigEntry

    def __init__(
        self,
        hass: HomeAssistant,
        config_entry: WeheatConfigEntry,
        session: OAuth2Session,
        heat_pump: HeatPumpDiscovery.HeatPumpInfo,
    ) -> None:
        """Initialize the data coordinator."""
        super().__init__(
            hass,
            config_entry=config_entry,
            logger=LOGGER,
            name=DOMAIN,
            update_interval=timedelta(seconds=ENERGY_UPDATE_INTERVAL),
        )
        self._heat_pump_data = HeatPump(
            API_URL, heat_pump.uuid, async_get_clientsession(hass)
        )

        self.session = session

    @override
    async def _async_update_data(self) -> HeatPump:
        """Fetch data from the API."""
        await self.session.async_ensure_token_valid()

        try:
            await self._heat_pump_data.async_get_energy(
                self.session.token[CONF_ACCESS_TOKEN]
            )
        except UnauthorizedException as error:
            raise ConfigEntryAuthFailed from error
        except EXCEPTIONS as error:
            raise UpdateFailed(error) from error

        return self._heat_pump_data


@dataclass
class WeheatData:
    """Data for the Weheat integration."""

    heat_pump_info: HeatPumpInfo
    data_coordinator: WeheatDataUpdateCoordinator
    energy_coordinator: WeheatEnergyUpdateCoordinator
