"""DataUpdateCoordinator for Fing integration."""

from dataclasses import dataclass, field
from datetime import timedelta
import logging

from fing_agent_api import FingAgent
from fing_agent_api.models import AgentInfoResponse, Device
import httpx

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_IP_ADDRESS, CONF_PORT
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import DOMAIN, UPNP_AVAILABLE

_LOGGER = logging.getLogger(__name__)

type FingConfigEntry = ConfigEntry[FingDataUpdateCoordinator]


@dataclass
class FingDataObject:
    """Fing Data Object."""

    network_id: str | None = None
    agent_info: AgentInfoResponse | None = None
    devices: dict[str, Device] = field(default_factory=dict)


class FingDataUpdateCoordinator(DataUpdateCoordinator[FingDataObject]):
    """Class to manage fetching data from Fing Agent."""

    def __init__(self, hass: HomeAssistant, config_entry: FingConfigEntry) -> None:
        """Initialize global Fing updater."""
        self._fing = FingAgent(
            ip=config_entry.data[CONF_IP_ADDRESS],
            port=int(config_entry.data[CONF_PORT]),
            key=config_entry.data[CONF_API_KEY],
        )
        self._upnp_available = config_entry.data[UPNP_AVAILABLE]
        update_interval = timedelta(seconds=30)
        super().__init__(
            hass,
            _LOGGER,
            name=DOMAIN,
            update_interval=update_interval,
            config_entry=config_entry,
        )

    async def _async_update_data(self) -> FingDataObject:
        """Fetch data from Fing Agent."""
        device_response = None
        agent_info_response = None
        try:
            device_response = await self._fing.get_devices()

            if self._upnp_available:
                agent_info_response = await self._fing.get_agent_info()

        except httpx.NetworkError as err:
            raise UpdateFailed("Failed to connect") from err
        except httpx.TimeoutException as err:
            raise UpdateFailed("Timeout establishing connection") from err
        except httpx.HTTPStatusError as err:
            if err.response.status_code == 401:
                raise UpdateFailed("Invalid API key") from err
            raise UpdateFailed(
                f"Http request failed -> {err.response.status_code} - {err.response.reason_phrase}"
            ) from err
        except httpx.InvalidURL as err:
            raise UpdateFailed("Invalid hostname or IP address") from err
        except (
            httpx.HTTPError,
            httpx.CookieConflict,
            httpx.StreamError,
        ) as err:
            raise UpdateFailed("Unexpected error from HTTP request") from err
        else:
            return FingDataObject(
                device_response.network_id,
                agent_info_response,
                {device.mac: device for device in device_response.devices},
            )
