#!/usr/bin/env python
import argparse
import json
import socket
import pprint as pp
import inspect
from minicash.utils.pow import POWGenerator


def getResponse(command):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('127.0.0.1', 2223))
        s.send(command.encode('utf-8'))
        response = s.recv(64000)
        s.close()
    except ConnectionError:
        print('Connection problem with the peer server. Probably the server is offline.'
              ' Please check the minicash.log file')
        exit()
    return str(response, 'utf-8')


def getPayload(command, params):
    payload = {
        'method': command,
        'params': params,
        'jsonrpc': '2.0',
        'id': 0,
    }
    return payload


def runCommand(commandName, args):
    params = dict(vars(args))
    _ = params.pop('func')
    datatosend = json.dumps(getPayload(commandName, [params]))
    try:
        datatosend = json.dumps(getPayload(commandName, [params]))
        response = json.loads(getResponse(datatosend))
    except json.decoder.JSONDecodeError as e:
        return {'Fail': {'Reason': 'JSONDecodeError', 'Message': e}}
    if 'error' in response:
        return {'Fail': {'Reason': 'json-rpc', 'Message': response['error']['message']}}
    return response['result']


def listLocalKeys(args):
    pp.pprint(runCommand(inspect.stack()[0][3], args))


def listPeers(args):
    pp.pprint(runCommand(inspect.stack()[0][3], args))


def getBalances(args):
    pp.pprint(runCommand(inspect.stack()[0][3], args))

def getAllBalances(args):
    pp.pprint(runCommand(inspect.stack()[0][3], args))

def getLedger(args):
    pp.pprint(runCommand(inspect.stack()[0][3], args))

def send(args):
    pp.pprint(runCommand(inspect.stack()[0][3], args))


def genPow(args):
    powGenerator = POWGenerator(args.key, args.difficulty, args.cores)
    result = powGenerator.getSolution()
    print('The solution is {}'.format(result))


def addKey(args):
    pp.pprint(runCommand(inspect.stack()[0][3], args))

def introduceKeyToLedger(args):
    pp.pprint(runCommand(inspect.stack()[0][3], args))

def stop(args):
    payload = {
        'method': 'stop',
        'params': [],
        'jsonrpc': '2.0',
    }
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('127.0.0.1', 2223))
        data = json.dumps(payload)
        s.send(data.encode('utf-8'))
        s.close()
    except ConnectionError:
        print('Connection problem with the server. Probably the server is offline')
        exit()


## COMMAND LINE PARSER
parser = argparse.ArgumentParser()
subparser = parser.add_subparsers()
# list-nodes subcommand
listnodes_cmd = subparser.add_parser('listpeers', help='List all online nodes in the network')
listnodes_cmd.set_defaults(func=listPeers)
# getledger subcommand
getledger_cmd = subparser.add_parser('getledger', help='Print the current ledger')
getledger_cmd.set_defaults(func=getLedger)
# getloginfo subcommand
introduceKeyToLedger_cmd = subparser.add_parser('introducekeytoledger', help='Introduce the key'
                                                ' to the ledger')
introduceKeyToLedger_cmd.add_argument('keytoadd', help='Key to add to the ledger')
introduceKeyToLedger_cmd.set_defaults(func=introduceKeyToLedger)
# listlocalkeys subcommand
listlocalkeys_cmd = subparser.add_parser('listlocalkeys', help='List all local keys fingerprints')
listlocalkeys_cmd.set_defaults(func=listLocalKeys)
# gen-pow subcommand
pow_cmd = subparser.add_parser('gen-pow', help='Create proof of work')
pow_cmd.add_argument('--cores', type=int, choices=range(1, 65), help='How many cores to use',
                     default=8, metavar='<1-64>')
pow_cmd.add_argument('difficulty', type=int, choices=range(1, 21), help='How many leading zeros \
    at pow', metavar='<1-20>')
pow_cmd.add_argument('key', help='The gpg key fingerprint')
pow_cmd.set_defaults(func=genPow)
# add-key subcommand
addkey_cmd = subparser.add_parser('add-key', help='Add existing key in the node')
addkey_cmd.add_argument('--noupload', action='store_true', default=False,
     help='Don\'t pload key to keyserver')
addkey_cmd.add_argument('key', help='The gpg fingerprint')
addkey_cmd.add_argument('pow', type=int, help='The proof of work number')
addkey_cmd.set_defaults(func=addKey)
# get-balances subcommand
getbalances_cmd = subparser.add_parser('getbalances', help='Get the balances')
getbalances_cmd.set_defaults(func=getBalances)
# get-all-balances subcommand
getallbalances_cmd = subparser.add_parser('getallbalances', help='Get the balances of all the nodes')
getallbalances_cmd.set_defaults(func=getAllBalances)
# stop subcommand
stop_cmd = subparser.add_parser('stop', help='Stop the server')
stop_cmd.set_defaults(func=stop)
# send_subcommand
send_cmd = subparser.add_parser('send', help='Pay to other key')
send_cmd.add_argument('from', help='The output address fingerprint')
send_cmd.add_argument('to', help='The input address fingerprint')
send_cmd.add_argument('amount', type=float, help='The amount to send')
send_cmd.set_defaults(func=send)

if __name__ == '__main__':
    args = parser.parse_args()
    try:
        args.func(args)
    except AttributeError:
        print('You haven\'t entered any subcommand or argument')
