from abc import ABC, abstractproperty, abstractmethod
from collections import namedtuple
from typing import List, Any, Iterator, Sequence
from ruxit.plugin_state_machine import PluginEngine
from ruxit.package_utils.plugin_updater import PluginInfo

SelectedPlugins = namedtuple("SelectedPlugins", ["activated", "deactivated"])
PluginConfig = namedtuple("PluginConfig", ["properties", "fast_id", "enabled"])
NonExistingPlugin = namedtuple("NoneExistingPlugin", ["name", "entity_id", "fast_id"])

class EntityResolverIfc(ABC):
    @abstractmethod
    def resolve(self, selector, **kwargs):
        return
    @abstractmethod
    def get_snapshot(self):
        return


# wrapper for customizing engine
class PlatformAPI(ABC):

    @property
    @abstractmethod
    def is_local(self) -> bool:
        pass

    @property
    @abstractmethod
    def external_api(self):
        #returns native C++ API
        return

    @property
    @abstractmethod
    def entity_resolver(self):
        #returns instance of EntityResolverIfc
        pass

    @abstractmethod
    def data_update(self) -> bool:
        #return true if configuration is changed
        # and some plugins have to be started or stopped
        pass

    @abstractmethod
    def select_plugins(self, plugin_engines: List[PluginEngine], plugin_metadata: List[PluginInfo]) -> SelectedPlugins:
        #plugin_metadata list of PluginInfo
        #returns SelectedPlugins lists
        pass

    @abstractmethod
    def get_plugin_config(self, plugin_engine: PluginEngine, plugin_metadata: List[PluginInfo]) -> PluginConfig:
        #plugin_metadata list of PluginInfo
        #returns configuration description as PluginConfig
        pass
    
    @abstractmethod
    def get_not_existing_plugins(self, plugins: Sequence[PluginEngine]) -> Sequence[NonExistingPlugin]:
        #return of plugin names with configuration and not created
        pass

    @abstractmethod
    def additional_report_step(self, plugin_engine: PluginEngine) -> None:
        '''
        Allows the specific agent to perform special action during the reporting step.
        :param plugin_engine:
        :return:
        '''
        return

    @abstractmethod
    def create_engine(self, plugin_info: PluginInfo, activation_context) -> Any:
        return
