const { HDPrivateKey, PrivateKey } = require('bitcore-lib')
const { TemplateWarehouse, Compiler, DefaultFee } = require('@asimovdev/asimovjs')
const readlineSync = require('readline-sync')
const colors = require('colors')
const storage = require('./storage')
const { rpc, checkState } = require('./rpc')
const path = require('path');
const console = require('./console')
let Module = require('../lib/flow_4.0.1')
let compiler = new Compiler(Module)

let templateWarehouse = new TemplateWarehouse({
  chainRpcProvider: rpc
})



module.exports = {
  createTemplate: function(source, name, category, gasLimit, privateKey, feeValue, feeType) {

    return new Promise((resolve, reject) => {
      if (!source) {
        console.warn('.sol source file is not specified!')
        reject('')
      }
      source = path.resolve(process.cwd(), source)
      if (!name) {
        console.warn('template name is not specified!')
        reject('')
      }

      if (category == undefined) {
        console.warn('template category is not specified!')
        reject('')
      }
      if (!privateKey) {
        console.warn('private key is not specified!')
        reject('')
      }
      compiler.compileSol(source).then(res => {
        let { contracts, source } = res
        console.success('source file compiles successfully, please choose one template to upload:')
        let keys = []

        for (let key in contracts) {
          keys.push(key)
        }
        let index = readlineSync.keyInSelect(keys, 'which contract template to upload?')
        if (index == -1) {
          console.success('canceled')
          return
        }
        let contractName = keys[index]
        console.success('submitting template ' + contractName)
        let contract = contracts[contractName]
        let byteCode = contract.evm.bytecode.object
        let abi = contract.abi
        if (!byteCode) {
          console.warn('can not upload Interface as Contract')
          return
        }

        templateWarehouse.create({
          category: category,
          name: name,
          bytecode: byteCode,
          abi: JSON.stringify(abi),
          source: source,
          gasLimit: gasLimit,
          privateKey: privateKey,
          fee: {
            amount: feeValue,
            asset: feeType || '000000000000000000000000'
          }
        }).then(res => {
          checkState(res)
          resolve(res)
        }).catch(e => {
          reject(e)
        })
      }).catch(e => {
        reject(e)
      })
    })


  },
  createTemplateWithContractName: function(source, name, category, gasLimit, privateKey, cname, feeValue, feeType) {

    return new Promise((resolve, reject) => {
      if (!source) {
        console.warn('.sol source file is not specified!')
        reject('')
      }
      source = path.resolve(process.cwd(), source)
      if (!name) {
        console.warn('template name is not specified!')
        reject('')
      }

      if (category == undefined) {
        console.warn('template category is not specified!')
        reject('')
      }
      if (!privateKey) {
        console.warn('private key is not specified!')
        reject('')
      }

      compiler.compileSol(source).then(res => {
        let { contracts, source } = res

        let contractName = cname

        let contract = contracts[contractName]
        let byteCode = contract.evm.bytecode.object
        let abi = contract.abi

        templateWarehouse.create({
          category: category,
          name: name,
          bytecode: byteCode,
          abi: JSON.stringify(abi),
          source: source,
          gasLimit: gasLimit,
          privateKey: privateKey,
          fee: {
            amount: feeValue,
            asset: feeType || '000000000000000000000000'
          }
        }).then(res => {
          //console.log(res)
          resolve(res)
        }).catch(e => {
          reject(e)
        })
      }).catch(e => {
        reject(e)
      })
    })


  },
  listTemplate: function(category, page) {
    let pageSize = 10;

    if (category == undefined) {
      console.warn('template category is not specified!')
      return
    }
    let ca = Number(category)

    if (ca == NaN) {
      console.warn('template category should be a number!')
      return
    }

    let pa = Number(page)

    if (pa == NaN) {
      console.warn('template page should be a number!')
      return
    }

    return rpc.getContractTemplateList({
      category: ca,
      page: pa,
      pageSize: pageSize
    }).then(res => {
      console.log(res)
      let tempaltes = res && res.TemplateInfo || []
      tempaltes.forEach((t, index) => {
        let date = new Date(t.createTime * 1000)
        console.success((index + 1) + '. ' + t.name + '  ' + t.key + ' ' + date.getFullYear() + ' ' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes())
      })
    }).catch(e => {
      console.error(e)
    })
  },

  deployTemplate: function(id, args, gasLimit, privateKey, feeValue, feeType) {
    return new Promise((resolve, reject) => {
      let arguments = args || []
      let mainAccount = storage.getMainAccount()
      if(!privateKey) {
        if (mainAccount.pk) {
          privateKey =  mainAccount.pk
        } else {
          console.warn('please specify a private key or set a default account')
          reject('')
        }
      }

      templateWarehouse.deploy({
        templateId: id,
        arguments: arguments || [],
        gasLimit: gasLimit,
        privateKey: privateKey,
        amount: 0,
        asset: '000000000000000000000000',
        fee: {
          amount: feeValue,
          asset: feeType || '000000000000000000000000'
        }
      }).then(res => {
        checkState(res,true)
      })
    })
  },
  createAndDeployTemplate(source, name, category, gasLimit, privateKey, args, feeValue, feeType) {

    let count = 0
    let queryCount = 10
    let queryLoop = (txId, resolve, reject) => {
      rpc.getTransactionReceipt(txId).then(res => {
        console.log('waiting...')
        if (!res) {
          count++
          if (count >= queryCount) {
            reject(0)
            return
          }
          setTimeout(() => {
            queryLoop(txId, resolve, reject)
          }, 5000)
        } else if (res.status == 1) {
          resolve(1)
          return
        } else {
          reject(0)
          return
        }
      }).catch(e => {
        reject(e)
      })
    }
    return new Promise((resolve, reject) => {
      this.createTemplate(source, name, category, gasLimit, privateKey, feeValue, feeType).then(res => {
        let txId = res;
        let promise = new Promise((resolve, reject) => {

          queryLoop(txId, resolve, reject)

        })

        promise.then(res => {

          this.deployTemplate(txId, args, gasLimit, privateKey, feeValue, feeType)

        }).catch(e => {
          reject(e)
        })
        resolve(res)
      }).catch(e => {
        reject(e)
      })
    })
  }
}
