from functools import wraps

import retrying
import typing

import rsa
from aws_lambda_tools.common.response import Response
from aws_lambda_tools.logging.factory import LOGGING_FACTORY
from aws_lambda_tools.test.client import AWSTestClient
from aws_lambda_tools.test.resources_mapper import ResourcesMapper
from core_wallet_client.client.client import CoreWalletClientImpl

from conio_sdk.ioc import ioc_core_wallet, ioc_bittrade
from etc import settings


SELL_LIMIT = 1000
BUY_LIMIT = 7000

USER_LEVEL = 'SELL {} BUY {}'.format(SELL_LIMIT, BUY_LIMIT)


ONE_MINUTE = 60000
_HYPE_PRIVATE_KEY_DATA = b'''
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA1aYX3mtodPYVIPO8Vb2czaDEJhl3O8xaupLnA9tOeRnDrrTb
o5G8CnxSXXC9FssEcG/CNYyQY5Df8n+KkuATfZA/rbMUlvOVtOgvPJuzKL9SZCai
2V0V/qWlK8fuZWvKQzvtUqE/2y9cq+aCUHbrGj8qSo9eALNmz4s3RvV9GFhhx8uE
mTYHf3Pm89fbpoPCOpKGHEBLoqPkcKALl2zsgRwZqgG3tARKymcXpjhDwTtV5c+A
rSBBV3OFWZ6nxMe1GgXQZWuEi4JmO93eDQujyc/TfmqB1Q+VoXeqDwmBECjNOYd2
CueRmtwsILPBLoLhGkE+YpAEEPM4QgI7xb7zTwIDAQABAoIBAHaA1RZynxLY9+k6
KEmqjZHkzUeQsnkBpYV9PBQAjatQJiD+giFdEV8DjC/1+3vsCb9PzfojyGbhkcYR
BkznawgnfZqcDRyZaX1Zl/HXLu24CTwxzfwgzLVdLZt2Hv40ZpEaaU1+0UuDHrTe
e4OkIk2BobSPhwV+fNU7k+KRAd0BDTfzp7Vt1m0MCMNU55qUxo5KlNIUtv39Oxsm
wx8v4r+cZIIfJEeW0xSQHa5ZN8dwPgXbB1p97RhDl2j7UAnMM63smvQJ40MMcCx7
m6plzv4wd7+k384Sju5pjzO0pgW/Ne4XtCu6rqNWrI2miZ1xyH2JuQR73F0KulKX
jNusFjECgYEA8+vvRNGTn+8bFwnq3aLqtlzPnqe6pcpUGhTeHzt/g9izYOIO3t6D
hYZlJbN4n3C6RkcJ4wMFgN6SbW+nzw09dca6j465BkXfffkt4g8kWeCl5a0hbY0z
/JIFzTo8X32sIvboVvjb61nDoW6egdCufuN28Ib9f1M7PeMqiVJfTIcCgYEA4Dpn
9ahQEoNWFowEXdghEfxU5nqIVJr6OVvZmRqH+haCe3Oo+Ap9WasdXBFOdjePRPkc
sbtV3K0ER59Z+dRrXrLWOtOw9LSOmGSFWSuepKN/JJ0wJyBssYMM1ZqVGnTg/nqO
Ja/1lwOnxZbezrrQtwm8+6K7zWt58EMnDiRLXPkCgYArknrUZUekqzbAn9Hns6GP
3/ZqlfW+he0OF6oyFBPMPpqUdO1JHKCL6p0I5g1nFeEAitIWTkTeZ2PqzqZAU1Im
RtCuskUU/MhWnXt3xVKuB3Y7F/k/s5iUxpTouz1rpWxpdoe8eYn3ebp7jOIduGRj
YEiv4L1J0Fllzb2ceC1z4wKBgAT9B6cNcYqX5WhnAQndbw7pYDIoc7P+Jqb0BilD
z9aefZSlhBLQmO1Pwz1zHR3AKq3MJPlHQ6e/KaM2Rlgqg6D9tYplf0BSbAGz6suL
DuJ2yLNV0+Zq8EAavERcRgjqpL7Elzj7aylK6YaZzqcmvNH1o4CtpCPzyiiwNcQ4
xnxxAoGAGC+baVi02c9ZjS3/Le8MPL12/r8CJrMYYLAONuijspsNDDke8cs3Jl4L
5uTiXWW+6kBo0rgfbF6k09IkcYkcOu5fwl/cvXZw64Z+H4g7bcbQv+OcKQx1/nsf
WqOOUzGI+AUZX3MS1SalCbf2r5zajezR+pLYqGQMBV4Ix77A6Lw=
-----END RSA PRIVATE KEY-----
'''
HYPE_PRIVATE_KEY = rsa.PrivateKey.load_pkcs1(_HYPE_PRIVATE_KEY_DATA)


BearerToken = typing.NewType('BearerToken', str)
AuthenticationHeaders = typing.NamedTuple(
    'AuthenticationHeaders',
    (
        ('Authorization', BearerToken),
    )
)
BIP32PrivateKey = typing.NewType('BIP32PrivateKey', str)

Satoshi = typing.NewType('Satoshi', int)
BTCAddress = typing.NewType('BTCAddress', str)


def moving_coins(fun):
    @wraps(fun)
    def _wrapper(*a, **kw):
        try:
            return fun(*a, **kw)
        finally:
            # noinspection PyBroadException
            try:
                @retrying.retry(
                    wait_exponential_multiplier=100,
                    wait_exponential_max=1000, stop_max_delay=60000,
                    retry_on_exception=lambda e: isinstance(e, AssertionError)
                )
                def _f():
                    print('Charging back BTC')
                    CoreWalletClientImpl(settings.CORE_WALLET_URL, settings.CORE_WALLET_SECRET_KEY)\
                        .move_bitcoins_back_to_bitcoind()

                @retrying.retry(
                    wait_exponential_multiplier=100,
                    wait_exponential_max=1000, stop_max_delay=60000,
                    retry_on_exception=lambda e: isinstance(e, AssertionError)
                )
                def _g():
                    wallet_info = ioc_core_wallet.core_wallet_client.get_wallet_info(
                        ioc_bittrade.bittrade_client.get_deposit_wallet().wallet_id,
                        invalidate_cache=True
                    )
                    if wallet_info.balance != 0 or wallet_info.incoming_balance != 0:
                        raise ValueError
                _f()
                _g()

            except Exception:
                LOGGING_FACTORY.test.exception('Could not charge back BTC')

    return _wrapper


class VersionedAWSTestClient(AWSTestClient):
    def __init__(self, resources_mapper: ResourcesMapper, version: str):
        super().__init__(resources_mapper)
        self._version = version

    def post(self, *a, headers: typing.Dict[str, str] = None, **kw) -> Response:
        return super().post(*a, headers=self._add_version(headers), **kw)

    def get(self, *a, headers: typing.Dict[str, str] = None, **kw) -> Response:
        return super().get(*a, headers=self._add_version(headers), **kw)

    def put(self, *a, headers: typing.Dict[str, str] = None, **kw) -> Response:
        return super().put(*a, headers=self._add_version(headers), **kw)

    def delete(self, *a, headers: typing.Dict[str, str] = None, **kw) -> Response:
        return super().delete(*a, headers=self._add_version(headers), **kw)

    def _add_version(self, headers: typing.Dict[str, str]) -> dict:
        if not headers:
            headers = dict()
        headers['versioncode'] = self._version
        return headers
