#
# Copyright (c) 2000, 2099, trustbe and/or its affiliates. All rights reserved.
# TRUSTBE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
#
#

from abc import abstractmethod, ABC
from typing import Any, Dict
from typing import Type, Generic

from mesh.macro import T, Inspector, Parameters, Returns
from mesh.macro import spi
from mesh.mpc.urn import URN


@spi(name='invoker', pattern="*")
class Invoker(Generic[T], ABC):
    """
    Invoke the next invoker.
    """

    @abstractmethod
    async def run(self, invocation: "Invocation") -> Any:
        pass


class Invocation(ABC):

    @abstractmethod
    def get_proxy(self) -> Invoker[T]:
        """
         Get the delegate target object.
        :return: proxy target
        """
        pass

    @abstractmethod
    def get_inspector(self) -> Inspector:
        """
        Get the invocation inspector.
        :return: inspector
        """
        pass

    @abstractmethod
    def get_parameters(self) -> Parameters:
        """
        Invoke parameters. include arguments and parameters.
        :return: parameters
        """
        pass

    @abstractmethod
    def get_arguments(self) -> [Any]:
        """
        Invoke parameters.
        :return: arguments
        """
        pass

    @abstractmethod
    def get_attachments(self) -> Dict[str, str]:
        """
        Get the attachments. The attributes will be serialized.
        :return: attachments
        """
        pass

    @abstractmethod
    def get_execution(self) -> "Execution":
        """ Get the invocation execution. """
        pass

    @abstractmethod
    def get_urn(self) -> URN:
        """
        Get the invoke urn.
        :return:
        """
        pass


class Execution(Invoker[T], Generic[T], ABC):
    """

    """

    @abstractmethod
    def schema(self) -> T:
        """ Execution schema. """
        pass

    @abstractmethod
    def inspect(self) -> Inspector:
        """ Inspect execution. """
        pass

    @abstractmethod
    def intype(self) -> Type[Parameters]:
        """ Execution input type. """
        pass

    @abstractmethod
    def retype(self) -> Type[Returns]:
        """ Execution output return type. """
        pass

    @abstractmethod
    def inflect(self) -> Parameters:
        """ Reflect input type. """
        pass

    @abstractmethod
    def reflect(self) -> Returns:
        """ Reflect output return type. """
        pass


class ServiceInvocation(Generic[T], Invocation):

    def __init__(self, proxy: Invoker[T], inspector: Inspector, parameters: Parameters, execution: Execution, urn: URN):
        self.proxy = proxy
        self.inspector = inspector
        self.parameters = parameters
        self.execution = execution
        self.urn = urn

    def get_proxy(self) -> Invoker[T]:
        return self.proxy

    def get_inspector(self) -> Inspector:
        return self.inspector

    def get_parameters(self) -> Parameters:
        return self.parameters

    def get_arguments(self) -> [Any]:
        return self.parameters.get_arguments()

    def get_attachments(self) -> Dict[str, str]:
        return self.parameters.get_attachments()

    def get_execution(self) -> Execution:
        return self.execution

    def get_urn(self) -> URN:
        return self.urn
