import json
import requests
from six import integer_types
from decimal import Decimal
from wowstash import config


PICOWOW = Decimal('0.00000000001')

class JSONRPC(object):
    def __init__(self, proto, host, port, username='', password=''):
        self.endpoint = '{}://{}:{}/'.format(
            proto, host, port
        )
        self.auth = requests.auth.HTTPDigestAuth(
            username, password
        )

    def make_rpc(self, method, params={}, json_rpc=True):
        if json_rpc:
            endpoint = self.endpoint + "json_rpc"
        else:
            endpoint = self.endpoint + method

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


class Wallet(JSONRPC):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        if 'height' in self.height():
            self.connected = True
        else:
            self.connected = False

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

    def spend_key(self):
        return self.make_rpc('query_key', {'key_type': 'spend_key'})['key']

    def view_key(self):
        return self.make_rpc('query_key', {'key_type': 'view_key'})['key']

    def seed(self):
        return self.make_rpc('query_key', {'key_type': 'mnemonic'})['key']

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

    def get_address(self, account_index=0):
        data = {'account_index': account_index}
        address = self.make_rpc('get_address', data)['address']
        return address

    def get_balances(self, account_index=0):
        data = {'account_index': account_index}
        balance = self.make_rpc('get_balance', data)
        return (balance['balance'], balance['unlocked_balance'])

    def get_transfers(self, account_index=0):
        data = {
            'account_index': account_index,
            'in': True,
            'out': True,
            'pending': True,
            'failed': True,
            'pool': True
        }
        return self.make_rpc('get_transfers', data)

    def transfer(self, dest_address, atomic_amount, type='transfer', account_index=0):
        data = {
            'account_index': account_index,
            'priority': 0,
            'unlock_time': 0,
            'get_tx_key': True,
            'get_tx_hex': True,
            'new_algorithm': True,
            'do_not_relay': False,
            'ring_size': 22
        }
        if type == 'sweep_all':
            data['address'] = dest_address
            transfer = self.make_rpc('sweep_all', data)
        else:
            data['destinations'] = [{
                'address': dest_address,
                'amount': atomic_amount
            }]
            transfer = self.make_rpc('transfer', data)
        return transfer


class Daemon(JSONRPC):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def info(self):
        return self.make_rpc('get_info', {}, json_rpc=False)

    def height(self):
        return self.make_rpc('get_height', {}, json_rpc=False)


def to_atomic(amount):
    if not isinstance(amount, (Decimal, float) + 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**11)

def from_atomic(amount):
    return (Decimal(amount) * PICOWOW).quantize(PICOWOW)

def as_wownero(amount):
    return Decimal(amount).quantize(PICOWOW)


daemon = Daemon(
    proto=config.DAEMON_PROTO,
    host=config.DAEMON_HOST,
    port=config.DAEMON_PORT,
    username=config.DAEMON_USER,
    password=config.DAEMON_PASS
)
