const _ = require('lodash')
const bitcoin = require('bitcoinjs-lib');
const BigNumber = require('bignumber.js');
const coinSelect = require('coinselect')
const axios = require('axios')
const config = require('./configLoad');

class btcBasic{
    constructor(chain){
        this.config = config[chain]
      }
    
    get = async (url) => {
        return (await axios.get(this.config.URL + url)).data
    }
      
    post = async (url, data) => {
        return (await axios.post(this.config.URL + url, data)).data
    }

    getAddressUtxo = async (address) => {
        const result = await this.get(`/address/${address}?unspent=true&limit=1000`)
        return this.utxoMapper(result)
    }

    utxoMapper = (utxos) => {
        utxos = utxos.map(utxo => {
          const out = {}
          const amount = new BigNumber(utxo.value).div(1e8).toNumber()
          _.set(out, 'address', utxo.address)
          _.set(out, 'txid', utxo.mintTxid)
          _.set(out, 'txId', utxo.mintTxid)
          _.set(out, 'vout', utxo.mintIndex)
          _.set(out, 'scriptPubKey', utxo.script)
          _.set(out, 'amount', amount)
          _.set(out, 'satoshis', utxo.value)
          _.set(out, 'height', utxo.mintHeight)
          _.set(out, 'confirmations', utxo.confirmations)
          return _.assign(utxo, out)
        })
        return utxos
      }

    getfeeRate = async() => {
        const result = await this.get('/fee/7')
        return result.feerate
    }

    sendTx = async(rawtx) =>{
        let result
        try {
            result = await this.post('/tx/send', { rawTx: rawtx })
        } catch (err) {
            console.log(err)
            throw new Error('broadcast tx failed ')}
        return result
    }

    async getUtxos() {
        const froms = _.map(this.config.KEYPAIR,'ADDRESS')
        const utxoSet = new Set();

        for (const address of froms) {
        const utxos = await this.getAddressUtxo(address)
        utxos.forEach(utxo => {
            utxoSet.add(JSON.stringify(utxo))
            });
        }
        const uniqueUTXOs = Array.from(utxoSet).map(utxoString => JSON.parse(utxoString))
        return uniqueUTXOs
    }

    network = () => {
        return bitcoin.networks.testnet
    }

    genAddressByRandom = () => {
        const network = this.network()
        const keyPair = bitcoin.ECPair.makeRandom({ network })
        const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network })
        console.log(`Address: ${address},PrivateKey: ${keyPair.toWIF()}`)
        return address
    }
  

    async sendBTC(address,amount){
        const feePrice = await this.getfeeRate()
        const feeRate = new BigNumber(feePrice).times(1e8).dividedBy(100).integerValue(BigNumber.ROUND_DOWN).toNumber()
        const value = new BigNumber(amount).times(1e8).toNumber()
        let targets = [{
            address,
            value
        }]
        //const froms 
        // 扩展成50个output
        // targets = Array(12).fill().map(() => targets).flat();
        const utxos = await this.getUtxos()
        const {inputs, outputs, fee} = coinSelect(utxos,targets,feeRate)
        if (inputs && outputs){
            //build tx
            const filledOutputs = outputs.map(output => {
                if (!output.address) {
                  output.address = inputs[0].address; // 在这里设置默认值
                }
                return output;
            })
            const network = this.network()
            const tx = new bitcoin.TransactionBuilder(network)
            inputs.forEach((e)=>tx.addInput(e.txid,e.vout))
            filledOutputs.forEach((e)=>tx.addOutput(e.address,e.value))

            //sign tx
            const froms = this.config.KEYPAIR
            let signer,priKey
            for (let i =0;i<inputs.length;i++){
                priKey = _.find(froms, function(o) { return o.ADDRESS == inputs[i].address})
                signer = bitcoin.ECPair.fromWIF(priKey.PRIKEY, network)
                tx.sign(i,signer)
            }
            
            //send tx
            const rawtx = tx.build().toHex()
            const hash = await this.sendTx(rawtx)
            console.log(`Transfer ${amount} BTC to ${address}. Transaction Hash: ${hash.txid}`);

        } else {
            console.log(inputs, outputs, fee)
            throw new Error('not enough utxos!!!')
        }

        

    }
}

module.exports = btcBasic