#!/usr/bin/env python

import argparse
import getpass
import sys
from binascii import hexlify

from ecdsa import SigningKey, SECP256k1

from cryptux.bitcoin.gen_addr import bitcoin_addr_from_priv_key_wif
from cryptux.bitcoin.gen_addr import bitcoin_addr_from_priv_key_hex
from cryptux.bitcoin.gen_addr import guess_wif_details
from cryptux.bitcoin.constants import MAINNET, TESTNET
from cryptux.bitcoin.constants import COMPRESSED, UNCOMPRESSED
from cryptux.bitcoin.wif import priv_key_to_wif

# https://pymotw.com/2/getpass/
# https://github.com/pexpect/pexpect

if sys.version_info[0] == 2:
    input = raw_input


def bitcoin_addr_from_wif():
    '''Generate Bitcoin address by requesting WIF'''
    priv_key_wif = getpass.getpass(prompt='WIF for Private Key: ')
    wif_details = guess_wif_details(priv_key_wif)
    bitcoin_addr = bitcoin_addr_from_priv_key_wif(priv_key_wif)
    return (bitcoin_addr, wif_details['network_type'], wif_details['key_fmt'])


def input_net_type_key_fmt():
    '''Utility function to get network type & pub key format'''
    net_types = [MAINNET, TESTNET]
    key_formats = [COMPRESSED, UNCOMPRESSED]
    network_type, key_fmt = None, None
    while network_type not in net_types:
        network_type = input('Network type (%s): ' % '/'.join(net_types))
        network_type = network_type.upper()
    while key_fmt not in key_formats:
        key_fmt = input('Public key format (%s): ' % '/'.join(key_formats))
        key_fmt = key_fmt.upper()
    return (network_type, key_fmt)


def bitcoin_addr_from_hex():
    '''Generate Bitcoin address by requesting HEX data'''
    network_type, key_fmt = input_net_type_key_fmt()
    priv_key_hex = getpass.getpass(prompt='HEX for Private Key: ')
    bitcoin_addr = bitcoin_addr_from_priv_key_hex(priv_key_hex, network_type,
                                                  key_fmt)
    return (bitcoin_addr, network_type, key_fmt)


def bitcoin_addr_from_generator():
    '''Generate Private Key and then derive Bitcoin address'''
    network_type, key_fmt = input_net_type_key_fmt()
    sk = SigningKey.generate(curve=SECP256k1)
    priv_key_raw = sk.to_string()
    priv_key_wif = priv_key_to_wif(priv_key_raw, network_type, key_fmt)
    priv_key_hex = hexlify(priv_key_raw).upper().decode('utf-8')
    print('=' * 64)
    print('Remember to protect the Private Key!')
    print('=' * 32)
    print('Private Key in HEX: %s' % priv_key_hex)
    print('Private Key in WIF: %s' % priv_key_wif)
    bitcoin_addr1 = bitcoin_addr_from_priv_key_wif(priv_key_wif)
    bitcoin_addr2 = bitcoin_addr_from_priv_key_hex(priv_key_hex, network_type,
                                                  key_fmt)
    assert bitcoin_addr1 == bitcoin_addr2
    return (bitcoin_addr1, network_type, key_fmt)


BITCOIN_GEN_HELPERS = {
    'WIF': bitcoin_addr_from_wif,
    'HEX': bitcoin_addr_from_hex,
    'NEW': bitcoin_addr_from_generator,
}


def gen_bitcoin_addr_helper():
    '''Helper to collect inputs for Bitcoin address'''
    str_priv_key_fmts = '/'.join(BITCOIN_GEN_HELPERS.keys())
    priv_key_fmt = None
    while priv_key_fmt not in BITCOIN_GEN_HELPERS:
        priv_key_fmt = input(
            'Private key format (%s): ' % str_priv_key_fmts)
        priv_key_fmt = priv_key_fmt.upper()
    bitcoin_addr, network_type, key_fmt = BITCOIN_GEN_HELPERS[priv_key_fmt]()
    print('=' * 64)
    print('Network type: %s' % network_type)
    print('Public key format: %s' % key_fmt)
    print('Generated Bitcoin address: %s' % bitcoin_addr)
    print('=' * 64)
    return bitcoin_addr


COIN_ADDR_HELPERS = {
    'BITCOIN': gen_bitcoin_addr_helper,
}

parser = argparse.ArgumentParser()
parser.add_argument(
    '-t',
    '--coin-type',
    type=str,
    help='coin type to generate account address for',
    choices=COIN_ADDR_HELPERS.keys())
args = parser.parse_args()
if not args.coin_type:
    parser.print_help()
    exit(0)
if args.coin_type not in COIN_ADDR_HELPERS:
    raise Exception('Unsupported coin type')
else:
    COIN_ADDR_HELPERS[args.coin_type]()
