from __future__ import annotations
import warnings
from typing import Tuple, Set, Dict, List, NamedTuple, Optional, TYPE_CHECKING
import krpc.limits
import krpc.schema
from krpc.schema import KRPC_pb2
from krpc.types import TypeBase, ClassBase, WrappedClass, DocEnum, StaticMethod
from krpc.event import Event
if TYPE_CHECKING:
    from krpc.services import Client


# The classes, enumerations, structures and exceptions put on the service in
# __init__, declared for type checkers
if TYPE_CHECKING:

    class _EmptyServiceDefinitions:
        pass
else:
    _EmptyServiceDefinitions = object


class EmptyService(_EmptyServiceDefinitions):

    def __init__(self, client: Client) -> None:
        self._client = client
        # The classes, enumerations, structures and exceptions the service defines are
        # put on the service here, so that reaching one is an ordinary attribute lookup
        # and nothing has to intercept the lookups that do not name one - which is every
        # call, as a call goes through a procedure or a property. A class is bound to the
        # client it is reached through, so that its static methods use that client.
        self.__dict__.update(self._enumerations)
        self.__dict__.update(self._structs)
        self.__dict__.update(self._exceptions)
        for name, class_type in self._classes.items():
            self.__dict__[name] = WrappedClass(client, class_type)

    # Hidden from type checkers, so that they report a name the service does not define
    if not TYPE_CHECKING:

        def __getattr__(self, name):
            # Reached only once the ordinary lookup has failed, which for a service means
            # either a name it does not define, or one it does whose procedure or property
            # raised an AttributeError of its own. Python discards that error before calling
            # this, so it cannot be reported here; what can be done is to not report a member
            # that does exist as missing, which would point at the wrong thing entirely.
            cls = type(self)
            if hasattr(cls, name):
                raise AttributeError(
                    "'%s' object attribute '%s' raised AttributeError"
                    % (cls.__name__, name)
                )
            raise AttributeError(
                "'%s' object has no attribute '%s'" % (cls.__name__, name)
            )

    _classes = {
    }
    _enumerations = {
    }
    _structs = {
    }
    _exceptions = {
    }
