package bitcoin

import (
	. "commonapi"
	"encoding/json"
	"fmt"
	"time"
	"strconv"
	simplejson "github.com/go-simplejson"
	tml "github.com/toml-master"
)

var (
	Config      config
	CoinDataApi BitcoinDataApi
)

type Bitcoin struct {
	walletstatus bool
}

const (
	NameCoin = "BTC"
)

func (m Bitcoin) InitDriver(parm interface{}) bool {
	if m.initconfig() == false {
		return false
	}
	go m.getwalletinfo()
	return true
}

func (m Bitcoin) QueryByAddress(parm interface{}) ([]byte, error) {
	pjs := parm.(*simplejson.Json)

	address := pjs.Get("address").MustString()
	if len(address) == 0 {
		LOG("ERROR", "QueryByAddres input address is null!")
		return nil, fmt.Errorf(`{"errcode":%v,"msg":"%s"}`, PARM_ERR, getErrMsg(PARM_ERR, []byte("address is null")))
	}
	filedir, err := CoinDataApi.GetTxidsByAddres(address)
	if err == nil {
		return filedir, nil
	} else {
		LOG("ERROR", "GetTransByAddres err:%v", address)
		return nil, fmt.Errorf(`{"errcode":%v,"msg":"%s"}`, ADDRESS_ERR, getErrMsg(ADDRESS_ERR, nil))
	}
}

func (m Bitcoin) QueryByBlockId(parm interface{}) ([]byte, error) {
	pjs := parm.(*simplejson.Json)
	blockid := pjs.Get("blockid").MustString()
	if len(blockid) == 0 {
		return nil, fmt.Errorf(`{"errcode":%v,"msg":"%v"}`, PARM_ERR, getErrMsg(PARM_ERR, []byte("blockid is null")))
	}
	var blockheight uint64
	var err error
	var filedir []byte
	var backupblockheight uint64
	// Query trans by block hash
	if len(blockid) == 64 {
		blockheight, err = CoinDataApi.WalletGetBlockHeight(blockid)
		if err != nil {
			LOG("ERROR", " WalletGetBlockHeight error:%v", err.Error())
			return nil, fmt.Errorf(`{"errcode":%v,"msg":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
		}
	} else {
		blockheight, err = strconv.ParseUint(blockid, 10, 64)
		if err != nil {
			LOG("ERROR", " strconv.ParseUint error:%v", err.Error())
			return nil, fmt.Errorf(`{"errcode":%v,"msg":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
		}
	} // Query trans by block height

	//get parsed blockheight in CoinDb
	backupblockheight, err = CoinDataApi.GetCoinDbBlockHeight()
	if err != nil {
		LOG("ERROR", " GetCoinDbBlockHeight error:%v", err.Error())
		return nil, fmt.Errorf(`{"errcode":%v,"msg":"%s"}`, KNOWN_ERR, getErrMsg(KNOWN_ERR, []byte("Get CoinDb BlockHeight error")))
	}
	parsedblockheight := fmt.Sprintf("parsed blockheight %d", backupblockheight)
	LOG("DEBUG", " CoinDb BlockHeight is %v", backupblockheight)

	if blockheight > backupblockheight {
		LOG("ERROR", " blockheight:%v >  backupblockheight:%v", blockheight, backupblockheight)
		return nil, fmt.Errorf(`{"errcode":%v,"msg":"%s"}`, KNOWN_ERR, getErrMsg(KNOWN_ERR, []byte(parsedblockheight)))
	}

	filedir, err = CoinDataApi.GetTxidsByBlockHeight(blockheight)
	if err == nil {
		return filedir, nil
	} else {
		LOG("ERROR", "GetTransByBlockHeight err:%v", blockid)
		return nil, fmt.Errorf(`{"errcode":%v,"msg":"%s"}`, BLOCKID_ERR, getErrMsg(BLOCKID_ERR, nil))
	}
}

func (m Bitcoin) QueryByTransId(parm interface{}) ([]byte, error) {

	pjs := parm.(*simplejson.Json)
	transid := pjs.Get("transcationid").MustString()
	if len(transid) == 0 {
		return nil, fmt.Errorf(`{"errcode":%v,"msg":"%v"}`, PARM_ERR, getErrMsg(PARM_ERR, []byte("transid is null")))
	}
	filedir, err := CoinDataApi.GetTransBytxid(transid)
	if err == nil {
		return filedir, nil
	} else {
		LOG("ERROR", "GetTransBytxid err:%v", transid)
		return nil, fmt.Errorf(`{"errcode":%v,"msg":"%s"}`, TRANSINFO_ERR, getErrMsg(TRANSINFO_ERR, nil))
	}
}

func (m Bitcoin) QueryBlockHeight(parm interface{}) ([]byte, error) {
	blocknum, err := CoinDataApi.WalleGetBlockCount()
	if err != nil {
		LOG("ERROR", "WalleGetBlockCount err %v!", err.Error())
		return nil, fmt.Errorf(`{"errcode":%v,"msg":"%v"}`, BLOCKHEIGHT_ERR, getErrMsg(BLOCKHEIGHT_ERR, []byte(err.Error())))
	}

	resptmp := make(map[string]interface{})
	resptmp["errcode"] = 0
	resptmp["cointype"] = "BTC"
	resptmp["blocknum"] = blocknum

	jbuf, err := json.Marshal(resptmp)
	if err != nil {
		fmt.Println("Marshal err ")
		return nil, fmt.Errorf(`{"errcode":%v,"msg":"%v"}`, BLOCKHEIGHT_ERR, getErrMsg(BLOCKHEIGHT_ERR, nil))
	} else {
		return jbuf, nil
	}
}

//query blockinfo
func (m Bitcoin) QueryBlockInfo(parm interface{}) ([]byte, error) {
	return nil, nil
}

//查询入币信息
func (m Bitcoin) QueryTransInfo(parm interface{}) ([]byte, error) {

	return nil, nil
}

func (m Bitcoin) getwalletinfo() bool {
	fmt.Println("WalletInfo:")
	m.walletstatus = false

	for {

		if m.walletstatus == false {
			resp, err := CoinDataApi.WalletInfo()
			if err != nil {
				LOG("ERROR", "WalletInfo error:%v", err.Error())
				time.Sleep(time.Second * 1)
				continue
			}

			LOG("DEBUG", "WalletInfo resp:%v", string(resp))
			m.walletstatus = true
		}

		// back up block info to db
		CoinDataApi.backupblockinfo()
		time.Sleep(time.Second * time.Duration(Config.Sleeptime.Blockinterval))
		continue

	}
}

//config rpc from bitcoin.toml
func (m Bitcoin) initconfig() bool {
	if _, err := tml.DecodeFile("./src/bitcoin/bitcoin.toml", &Config); err != nil {
		fmt.Println(err)
		return false
	}

	fmt.Printf("%+v\n", Config)

	//inti rpcconfig
	User := Config.Rpc.Rpcuser
	Password := Config.Rpc.Rpcpassword
	Host := Config.Rpc.Rpchost
	Port := Config.Rpc.Rpcport

	CoinDataApi.InitRpcConf(User, Password, Host, Port)

	initErr()

	//init bitcoin db
	bitcoindb.InitGoleveldb()
	return true
}

func init() {
	Register(NameCoin, &Bitcoin{})
}
