package bitcoin

import (
	"encoding/json"
	"fmt"

	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/errors"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"github.com/syndtr/goleveldb/leveldb/util"
)

type goleveldb struct {
	mdb *leveldb.DB
}

type goLevelDBBatch struct {
	db    *goleveldb
	batch *leveldb.Batch
}

type Batch interface {
	Set(key, value []byte)
	Delete(key []byte)
	Write() error
}

var bitcoindb goleveldb

func (m *goleveldb) InitGoleveldb() bool {
	var err error
	var dbpath string

	dbPathLen := len(Config.Db.DbPath)
	if Config.Db.DbPath[dbPathLen-1] == '/' {
		dbpath = fmt.Sprintf("%sbitcoindb", Config.Db.DbPath)
	} else {
		dbpath = fmt.Sprintf("%s/bitcoindb", Config.Db.DbPath)
	}
	fmt.Println("bitcoin goleveldb :", dbpath)
	m.mdb, err = leveldb.OpenFile(dbpath, nil)

	if err != nil {
		fmt.Println(err)
		return false
	}
	return true
}

func (m *goleveldb) Put(key, value []byte) error {
	err := m.mdb.Put(key, value, nil)
	if err != nil {
		return err
	}
	return nil
}

func (m *goleveldb) Get(key []byte) ([]byte, error) {
	res, err := m.mdb.Get(key, nil)
	if err != nil {
		if err == errors.ErrNotFound {
			return nil, nil
		} else {
			return nil, err
		}
	}
	return res, nil
}

func (m *goleveldb) Delete(key []byte) error {

	err := m.mdb.Delete(key, nil)
	if err != nil {
		return err
	}
	return nil
}
func (m *goleveldb) DeleteSync(key []byte) error {

	err := m.mdb.Delete(key, &opt.WriteOptions{Sync: true})
	if err != nil {
		return err
	}
	return nil
}
func (m *goleveldb) Close() {
	m.mdb.Close()
}

func (m *goleveldb) NewBatch() Batch {
	batch := new(leveldb.Batch)
	return &goLevelDBBatch{m, batch}
}

func (mBatch *goLevelDBBatch) Set(key, value []byte) {
	mBatch.batch.Put(key, value)
}

func (mBatch *goLevelDBBatch) Delete(key []byte) {
	mBatch.batch.Delete(key)
}

func (mBatch *goLevelDBBatch) Write() error {
	err := mBatch.db.mdb.Write(mBatch.batch, nil)
	if err != nil {
		return err
	}
	return nil
}

func (m *goleveldb) PrefixScan(key []byte) ([]byte, error) {

	var txid string
	var jbuf []byte
	var err error
	outputsArr := make([]string, 0)
	iter := m.mdb.NewIterator(util.BytesPrefix(key), nil)
	for iter.Next() {
		value := iter.Value()

		if err = json.Unmarshal([]byte(value), &txid); err != nil {
			fmt.Println("Unmarshal err :", err.Error())
			return nil, err
		}
		outputsArr = append(outputsArr, txid)
	}
	iter.Release()
	err = iter.Error()
	if err != nil {
		return nil, err
	}
	if jbuf, err = json.Marshal(outputsArr); err != nil {
		fmt.Println("Marshal err :", err.Error())
		return nil, err
	}
	return jbuf, nil
}
