from typing import (Any, Union, Type)  # noqa: F401

from ..keys.datatypes import (
    LazyBackend,
    PublicKey,
    PrivateKey,
    Signature,
)
from eth_keys.exceptions import (
    ValidationError,
)
from eth_keys.validation import (
    validate_message_hash,
)


# These must be aliased due to a scoping issue in mypy
# https://github.com/python/mypy/issues/1775
_PublicKey = PublicKey
_PrivateKey = PrivateKey
_Signature = Signature


class KeyAPI(LazyBackend):
    #
    # datatype shortcuts
    #
    PublicKey = PublicKey  # type: Type[_PublicKey]
    PrivateKey = PrivateKey  # type: Type[_PrivateKey]
    Signature = Signature  # type: Type[_Signature]

    #
    # Proxy method calls to the backends
    #
    def ecdsa_sign(self,
                   message_hash,  # type: bytes
                   private_key  # type: _PrivateKey
                   ):
        # type: (...) -> _Signature
        validate_message_hash(message_hash)
        if not isinstance(private_key, PrivateKey):
            raise ValidationError(
                "The `private_key` must be an instance of `eth_keys.datatypes.PrivateKey`"
            )
        signature = self.backend.ecdsa_sign(message_hash, private_key)
        if not isinstance(signature, Signature):
            raise ValidationError(
                "Backend returned an invalid signature.  Return value must be "
                "an instance of `eth_keys.datatypes.Signature`"
            )
        return signature

    def ecdsa_verify(self,
                     message_hash,  # type: bytes
                     signature,  # type: _Signature
                     public_key  # type: _PublicKey
                     ) -> bool:
        if not isinstance(public_key, PublicKey):
            raise ValidationError(
                "The `public_key` must be an instance of `eth_keys.datatypes.PublicKey`"
            )
        return self.ecdsa_recover(message_hash, signature) == public_key

    def ecdsa_recover(self,
                      message_hash,  # type: bytes
                      signature  # type: _Signature
                      ):
        # type: (...) -> _PublicKey
        validate_message_hash(message_hash)
        if not isinstance(signature, Signature):
            raise ValidationError(
                "The `signature` must be an instance of `eth_keys.datatypes.Signature`"
            )
        public_key = self.backend.ecdsa_recover(message_hash, signature)
        if not isinstance(public_key, _PublicKey):
            raise ValidationError(
                "Backend returned an invalid public_key.  Return value must be "
                "an instance of `eth_keys.datatypes.PublicKey`"
            )
        return public_key

    def private_key_to_public_key(self, private_key):
        if not isinstance(private_key, PrivateKey):
            raise ValidationError(
                "The `private_key` must be an instance of `eth_keys.datatypes.PrivateKey`"
            )
        public_key = self.backend.private_key_to_public_key(private_key)
        if not isinstance(public_key, PublicKey):
            raise ValidationError(
                "Backend returned an invalid public_key.  Return value must be "
                "an instance of `eth_keys.datatypes.PublicKey`"
            )
        return public_key


# This creates an easy to import backend which will lazily fetch whatever
# backend has been configured at runtime (as opposed to import or instantiation time).
lazy_key_api = KeyAPI(backend=None)

[((40, 8, 40, 43), 'eth_keys.validation.validate_message_hash', 'validate_message_hash', ({(40, 30, 40, 42): 'message_hash'}, {}), '(message_hash)', False, 'from eth_keys.validation import validate_message_hash\n'), ((69, 8, 69, 43), 'eth_keys.validation.validate_message_hash', 'validate_message_hash', ({(69, 30, 69, 42): 'message_hash'}, {}), '(message_hash)', False, 'from eth_keys.validation import validate_message_hash\n'), ((42, 18, 44, 13), 'eth_keys.exceptions.ValidationError', 'ValidationError', ({(43, 16, 43, 90): '"""The `private_key` must be an instance of `eth_keys.datatypes.PrivateKey`"""'}, {}), "(\n    'The `private_key` must be an instance of `eth_keys.datatypes.PrivateKey`')", False, 'from eth_keys.exceptions import ValidationError\n'), ((47, 18, 50, 13), 'eth_keys.exceptions.ValidationError', 'ValidationError', ({(48, 16, 49, 63): '"""Backend returned an invalid signature.  Return value must be an instance of `eth_keys.datatypes.Signature`"""'}, {}), "(\n    'Backend returned an invalid signature.  Return value must be an instance of `eth_keys.datatypes.Signature`'\n    )", False, 'from eth_keys.exceptions import ValidationError\n'), ((59, 18, 61, 13), 'eth_keys.exceptions.ValidationError', 'ValidationError', ({(60, 16, 60, 88): '"""The `public_key` must be an instance of `eth_keys.datatypes.PublicKey`"""'}, {}), "(\n    'The `public_key` must be an instance of `eth_keys.datatypes.PublicKey`')", False, 'from eth_keys.exceptions import ValidationError\n'), ((71, 18, 73, 13), 'eth_keys.exceptions.ValidationError', 'ValidationError', ({(72, 16, 72, 87): '"""The `signature` must be an instance of `eth_keys.datatypes.Signature`"""'}, {}), "(\n    'The `signature` must be an instance of `eth_keys.datatypes.Signature`')", False, 'from eth_keys.exceptions import ValidationError\n'), ((76, 18, 79, 13), 'eth_keys.exceptions.ValidationError', 'ValidationError', ({(77, 16, 78, 63): '"""Backend returned an invalid public_key.  Return value must be an instance of `eth_keys.datatypes.PublicKey`"""'}, {}), "(\n    'Backend returned an invalid public_key.  Return value must be an instance of `eth_keys.datatypes.PublicKey`'\n    )", False, 'from eth_keys.exceptions import ValidationError\n'), ((84, 18, 86, 13), 'eth_keys.exceptions.ValidationError', 'ValidationError', ({(85, 16, 85, 90): '"""The `private_key` must be an instance of `eth_keys.datatypes.PrivateKey`"""'}, {}), "(\n    'The `private_key` must be an instance of `eth_keys.datatypes.PrivateKey`')", False, 'from eth_keys.exceptions import ValidationError\n'), ((89, 18, 92, 13), 'eth_keys.exceptions.ValidationError', 'ValidationError', ({(90, 16, 91, 63): '"""Backend returned an invalid public_key.  Return value must be an instance of `eth_keys.datatypes.PublicKey`"""'}, {}), "(\n    'Backend returned an invalid public_key.  Return value must be an instance of `eth_keys.datatypes.PublicKey`'\n    )", False, 'from eth_keys.exceptions import ValidationError\n')]