"""Fetch last versions from webserver."""
import asyncio
from contextlib import suppress
from datetime import timedelta
import json
import logging

import aiohttp

from .const import (
    URL_HASSIO_VERSION,
    FILE_HASSIO_UPDATER,
    ATTR_HOMEASSISTANT,
    ATTR_HASSIO,
    ATTR_CHANNEL,
    ATTR_HASSOS,
    ATTR_HASSOS_CLI,
)
from .coresys import CoreSysAttributes
from .utils import AsyncThrottle
from .utils.json import JsonConfig
from .validate import SCHEMA_UPDATER_CONFIG
from .exceptions import HassioUpdaterError

_LOGGER = logging.getLogger(__name__)


class Updater(JsonConfig, CoreSysAttributes):
    """Fetch last versions from version.json."""

    def __init__(self, coresys):
        """Initialize updater."""
        super().__init__(FILE_HASSIO_UPDATER, SCHEMA_UPDATER_CONFIG)
        self.coresys = coresys

    async def load(self):
        """Update internal data."""
        with suppress(HassioUpdaterError):
            await self.fetch_data()

    async def reload(self):
        """Update internal data."""
        with suppress(HassioUpdaterError):
            await self.fetch_data()

    @property
    def version_homeassistant(self):
        """Return last version of Home Assistant."""
        return self._data.get(ATTR_HOMEASSISTANT)

    @property
    def version_hassio(self):
        """Return last version of Hass.io."""
        return self._data.get(ATTR_HASSIO)

    @property
    def version_hassos(self):
        """Return last version of HassOS."""
        return self._data.get(ATTR_HASSOS)

    @property
    def version_hassos_cli(self):
        """Return last version of HassOS cli."""
        return self._data.get(ATTR_HASSOS_CLI)

    @property
    def channel(self):
        """Return upstream channel of Hass.io instance."""
        return self._data[ATTR_CHANNEL]

    @channel.setter
    def channel(self, value):
        """Set upstream mode."""
        self._data[ATTR_CHANNEL] = value

    @AsyncThrottle(timedelta(seconds=60))
    async def fetch_data(self):
        """Fetch current versions from Github.

        Is a coroutine.
        """
        url = URL_HASSIO_VERSION.format(channel=self.channel)
        machine = self.sys_machine or "default"
        board = self.sys_hassos.board

        try:
            _LOGGER.info("Fetch update data from %s", url)
            async with self.sys_websession.get(url, timeout=10) as request:
                data = await request.json(content_type=None)

        except (aiohttp.ClientError, asyncio.TimeoutError) as err:
            _LOGGER.warning("Can't fetch versions from %s: %s", url, err)
            raise HassioUpdaterError() from None

        except json.JSONDecodeError as err:
            _LOGGER.warning("Can't parse versions from %s: %s", url, err)
            raise HassioUpdaterError() from None

        # data valid?
        if not data or data.get(ATTR_CHANNEL) != self.channel:
            _LOGGER.warning("Invalid data from %s", url)
            raise HassioUpdaterError() from None

        try:
            # update supervisor version
            self._data[ATTR_HASSIO] = data["supervisor"]

            # update Home Assistant version
            self._data[ATTR_HOMEASSISTANT] = data["homeassistant"][machine]

            # update hassos version
            if self.sys_hassos.available and board:
                self._data[ATTR_HASSOS] = data["hassos"][board]
                self._data[ATTR_HASSOS_CLI] = data["hassos-cli"]

        except KeyError as err:
            _LOGGER.warning("Can't process version data: %s", err)
            raise HassioUpdaterError() from None

        else:
            self.save_data()
