import requests
import six
import json
import operator
from decimal import Decimal
from app import config


class WalletRPC(object):
    def __init__(self, rpc_endpoint, username='', password=''):
        self.endpoint = f'{rpc_endpoint}/json_rpc'
        self.auth = requests.auth.HTTPDigestAuth(
            username, password
        )

    def make_wallet_rpc(self, method, params={}):
        r = requests.get(
            self.endpoint,
            data=json.dumps({'method': method, 'params': params}),
            auth=self.auth
        )
        if 'error' in r.json():
            return r.json()['error']
        else:
            return r.json()['result']

    def height(self):
        return self.make_wallet_rpc('get_height', {})

    def addresses(self, account=0, addr_indices=None):
        qdata = {'account_index': account}
        if addr_indices:
            qdata['address_index'] = addr_indices
        _addresses = self.make_wallet_rpc('get_address', qdata)
        addresses = [None] * (max(map(operator.itemgetter('address_index'), _addresses['addresses'])) + 1)
        for _addr in _addresses['addresses']:
            addresses[_addr['address_index']] = _addr['address']
        return addresses

    def new_address(self, account=0, label=None):
        data = {'account_index': account, 'label': label}
        _address = self.make_wallet_rpc('create_address', data)
        return (_address['address_index'], _address['address'])

    def balances(self, account=0):
        data = {'account_index': account}
        _balance = self.make_wallet_rpc('get_balance', data)
        return (_balance['balance'], _balance['unlocked_balance'])

    def transfer(self, address, amount):
        data = {
            'account_index': 0,
            'destinations': [{'address': address, 'amount': amount}],
            'priority': 1,
            'unlock_time': 0,
            'get_tx_key': True,
            'get_tx_hex': False,
            'new_algorithm': True,
            'do_not_relay': False,
        }
        transfer = self.make_wallet_rpc('transfer', data)
        return transfer

    def incoming_transfers(self, subaddress_index):
        data = {
            'subaddr_indices': [subaddress_index],
            'transfer_type': 'all'
        }
        return self.make_wallet_rpc('incoming_transfers', data)

    def get_transfers(self, subaddress_index=None):
        if subaddress_index:
            indices = [subaddress_index]
        else:
            indices = None
        data = {
            'in': True,
            'out': True,
            'subaddr_indices': indices
        }
        return self.make_wallet_rpc('get_transfers', data)

    def get_balance(self, subaddress_index):
        data = {
            'address_indices': [subaddress_index]
        }
        _balance = self.make_wallet_rpc('get_balance', data)
        res = _balance['per_subaddress'][0]
        return (res['balance'], res['unlocked_balance'])


class CoinUtils(object):
    def __init__(self):
        pass

    def to_atomic(self, amount):
        if not isinstance(amount, (Decimal, float) + six.integer_types):
            raise ValueError("Amount '{}' doesn't have numeric type. Only Decimal, int, long and "
                    "float (not recommended) are accepted as amounts.")
        return int(amount * 10**self.decimal_points)

    def from_atomic(self, amount):
        return (Decimal(amount) * self.full_notation).quantize(self.full_notation)

    def as_real(self, amount):
        real = Decimal(amount).quantize(self.full_notation)
        return float(real)

class Wownero(CoinUtils):
    def __init__(self):
        self.decimal_points = 11
        self.full_notation = Decimal('0.00000000001')

class Monero(CoinUtils):
    def __init__(self):
        self.decimal_points = 12
        self.full_notation = Decimal('0.000000000001')

wow_wallet = WalletRPC(
    config.WOW_WALLET_RPC_ENDPOINT,
    config.WOW_WALLET_RPC_USER,
    config.WOW_WALLET_RPC_PASS
)

xmr_wallet = WalletRPC(
    config.XMR_WALLET_RPC_ENDPOINT,
    config.XMR_WALLET_RPC_USER,
    config.XMR_WALLET_RPC_PASS
)

wownero = Wownero()
monero = Monero()
