from defence360agent.rpc_tools import ValidationError
from defence360agent.rpc_tools.lookup import RootEndpoints, bind
from defence360agent.utils import Scope
from im360.subsys.features import get_applicable_features
from defence360agent.subsys.features.abstract_feature import (
    FeatureError,
    FeatureStatus,
)


class FeaturesEndpoints(RootEndpoints):
    SCOPE = Scope.IM360

    @bind("features", "list")
    async def feature_list(self):
        return {"items": list(get_applicable_features().keys())}

    @bind("features", "install")
    async def feature_install(self, name):
        return await self.call("install", name)

    @bind("features", "remove")
    async def feature_remove(self, name):
        return await self.call("remove", name)

    @bind("features", "status")
    async def feature_status(self, name):
        return await self.call("status", name)

    async def call(self, action, name):
        try:
            _cls = get_applicable_features()[name]
        except KeyError:
            raise ValidationError("Feature is not available: {}".format(name))
        else:
            if _cls is None:
                raise ValidationError(f"No implementation for feature: {name}")

        try:
            feature = await _cls(sink=self._sink).init()
            return await getattr(feature, action)()
        except FeatureError as e:
            # implemented new format for status, but not for install/remove yet
            # also will be nice to move log file path to status response
            # because now, if status returned "installing", UI have to call
            # "install" (!) to get log file path
            if action == "status":
                return {
                    "items": {
                        "status": FeatureStatus.ERROR,
                        "message": str(e),
                    }
                }
            else:
                raise ValidationError(str(e))
