import { networks } from 'bitcoinjs-lib';
import { Unit } from 'bitcore-lib'
import { UTXO } from '../../interfaces/UTXO';
import * as common from '../../common';
import * as constants from '../../common/constants';
/**
 * Generate Bitcoin wallet
 * @param testnet testnet or mainnet version of address
 * @param mnemonic mnemonic seed to use
 * @returns wallet
 */
export const generateWallet = async (testnet: constants.NetworkType, mnemonic: string): Promise<{ mnemonic: string, accountExtPubkey: string, accountExtPrivatekey: string, bip32ExtPubkey: string, bip32ExtPrivatekey: string }> => {
  const network = getNetwork(testnet)
  const path = getPath(testnet)
  return common.generateWallet(mnemonic, path.substring(0, path.length - 2), network)
}

/**
 * Generate Bitcoin address from mnemonic
 * @param testnet testnet or mainnet version of address
 * @param mnemonic mnemonic seed to use
 * @param i derivation index of address to generate. Up to 2^31 addresses can be generated.
 * @returns blockchain address
 */
export const generateAddressFromMnemonic = async (testnet: constants.NetworkType, mnemonic: string, i: number) => {
  const network = getNetwork(testnet)
  const path = getPath(testnet)
  return common.generateAddressFromMnemonic(path.substring(0, path.length - 2), mnemonic, i, network)
}

/**
 * Convert Bitcoin Private Key to Address
 * @param testnet testnet or mainnet version of address
 * @param privkey private key to use
 * @returns blockchain address
 */
export const generateAddressFromPrivatekey = (testnet: constants.NetworkType, privkey: string) => {
  const network = getNetwork(testnet)
  return common.generateAddressFromPrivatekey(privkey, network)
}

/**
 * Generate Bitcoin private key from mnemonic seed
 * @param testnet testnet or mainnet version of address
 * @param mnemonic mnemonic to generate private key from
 * @param i derivation index of private key to generate.
 * @returns blockchain private key to the address
 */
export const generatePrivateKeyFromMnemonic = async (testnet: constants.NetworkType, mnemonic: string, i: number) => {
  const network = getNetwork(testnet)
  const path = getPath(testnet)
  return common.generatePrivateKeyFromMnemonic(mnemonic, path, i, network)
}

/**
 * Generate address from xpub
 * @param currency type of blockchain
 * @param testnet testnet or mainnet version of address
 * @param xpub extended public key to generate address from
 * @param i derivation index of address to generate. Up to 2^31 addresses can be generated.
 * @returns blockchain address
 */
export const generateAddressFromXPub = (testnet: constants.NetworkType, xpub: string, i: number) => {
  const network = getNetwork(testnet)
  return common.generateAddressFromXPub(xpub, i, network)
}

/**
 * Check bitcoin address is valid
 * @param testnet testnet or mainnet version of address
 * @param address bitcoin address
 * @returns true || false
 */
export const isValidAddress = (testnet: constants.NetworkType, address: string): boolean => {
  const network = getNetwork(testnet)
  return common.isValidAddress(address, network)
}

/**
 * Sign bitcoin tx offline
 * @param testnet testnet or mainnet version of address
 * @param outputs transaction outputs
 * @param privateKey sender private key
 * @param toAddress receiver
 * @param valueInBtc valut in btc
 * @returns rawTx
 */
export const signTxOffline = (testnet: constants.NetworkType, outputs: UTXO[], privateKey: string, toAddress: string, valueInBtc: number, changeAddress?: string): string => {
  const network = getNetwork(testnet)
  return common.signTxOffline(outputs, privateKey, toAddress, Unit.fromBTC(valueInBtc).toSatoshis(),network, changeAddress)
}

export const getNetwork = (testnet: constants.NetworkType) => {
  return testnet === 'mainnet' ? networks.bitcoin : networks.testnet
}

export const getPath = (testnet: constants.NetworkType) => {
  return testnet === 'mainnet' ? constants.BTC_DERIVATION_PATH : constants.TESTNET_DERIVATION_PATH
}