from moneywagon import (
    get_unspent_outputs, CurrentPrice, get_optimal_fee, PushTx,
    get_onchain_exchange_rates
)
from moneywagon.core import get_optimal_services, get_magic_bytes
from bitcoin import mktx, sign, pubtoaddr, privtopub
from .crypto_data import crypto_data

class Transaction(object):
    def __init__(self, crypto, hex=None, verbose=False):
        if crypto.lower() in ['nxt']:
            raise NotImplementedError("%s not yet supported" % crypto.upper())

        self.change_address = None
        self.crypto = crypto
        self.fee_satoshi = None
        self.outs = []
        self.ins = []
        self.onchain_rate = None

        self.verbose = verbose

        if hex:
            self.hex = hex

    def from_unit_to_satoshi(self, value, unit='satoshi'):
        """
        Convert a value to satoshis. units can be any fiat currency.
        By default the unit is satoshi.
        """
        if not unit or unit == 'satoshi':
            return value
        if unit == 'bitcoin' or unit == 'btc':
            return value * 1e8

        # assume fiat currency that we can convert
        convert = get_current_price(self.crypto, unit)
        return int(value / convert * 1e8)

    def add_raw_inputs(self, inputs, private_key=None):
        """
        Add a set of utxo's to this transaction. This method is better to use if you
        want more fine control of which inputs get added to a transaction.
        `inputs` is a list of "unspent outputs" (they were 'outputs' to previous transactions,
          and 'inputs' to subsiquent transactions).

        `private_key` - All inputs will be signed by the passed in private key.
        """
        for i in inputs:
            self.ins.append(dict(input=i, private_key=private_key))
            self.change_address = i['address']

    def _get_utxos(self, address, services, **modes):
        """
        Using the service fallback engine, get utxos from remote service.
        """
        return get_unspent_outputs(
            self.crypto, address, services=services,
            **modes
        )

    def private_key_to_address(self, pk):
        """
        Convert a private key (in hex format) into an address.
        """
        pub = privtopub(pk)
        pub_byte, priv_byte = get_magic_bytes(self.crypto)

        if priv_byte >= 128:
            priv_byte -= 128 #pybitcointools bug

        return pubtoaddr(pub, pub_byte)

    def add_inputs(self, private_key=None, address=None, amount='all', max_ins=None, password=None, services=None, **modes):
        """
        Make call to external service to get inputs from an address and/or private_key.