import asyncio

from dbus_next import BusType, DBusError, InvalidObjectPathError
from dbus_next.aio import MessageBus


class Rauc:
    """Interfaces with the system RAUC daemon via d-bus"""

    MAX_PROGRESS = 100
    DONE_MESSAGE = "Installing done."

    def __init__(self):
        self._bus = None
        self._installer = None

    async def connect(self) -> None:
        """Connect to d-bus"""
        self._bus = await MessageBus(bus_type=BusType.SYSTEM).connect()

        introspection = await self._bus.introspect("de.pengutronix.rauc", "/")
        proxy = self._bus.get_proxy_object("de.pengutronix.rauc", "/", introspection)
        self._installer = proxy.get_interface("de.pengutronix.rauc.Installer")

    async def getLastError(self, logger) -> str:
        """
        Retrieves the last error during a rauc installation.

        :return: The error or exception as string
        """
        result: str = await self._installer.get_last_error()
        if result:
            logger.info(f"LastError: {result}")
        return result

    async def installBundle(self, bundleFile: str) -> None:
        """Install the specified bundle in not booted slot

        RAUC daemon will start the process in the background

        :param bundleFile: path to bundle file
        """
        await self._installer.call_install_bundle(bundleFile, {})

    async def disconnect(self):
        if self._bus:
            self._bus.disconnect()
            await self._bus.wait_for_disconnect()

    async def checkInstallationDone(self, logger) -> bool:
        """
        During an installation of the rauc bundle the progress of the installation progress is retrieved via the d-bus API

        :return: A bool telling if installation is finished.
        """
        percentage, message, nestingDepth = await self._installer.get_progress()
        logger.info(f"{percentage:3d}% ({message})")
        return percentage == self.MAX_PROGRESS or message == self.DONE_MESSAGE
