package raftNode

import (
	"bytes"
	"fmt"
	"github.com/hashicorp/raft"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"io"
)

var (
	dbLogIndex = []byte("logsIndex")
)

func NewRaftFsm2(path string, durability Level) (*raftFsm2, error) {
	var wo opt.WriteOptions
	var opts opt.Options
	if durability <= Low {
		opts.NoSync = true
		wo.Sync = false
	} else {
		opts.NoSync = false
		wo.Sync = true
	}
	// Try to connect
	db, err := leveldb.OpenFile(path, &opts)
	if err != nil {
		return nil, err
	}
	_fsm := &raftFsm2{
		db:   db,
		path: path,
		wo:   &wo,
	}
	return _fsm, nil
}

type raftFsm2 struct {
	// db is the underlying handle to the db.
	db *leveldb.DB
	// The path to the Bolt database file
	path string
	wo   *opt.WriteOptions
}

func (that *raftFsm2) Find(tree, key string) interface{} {
	_rs, _err := that.Get([]byte(key))
	if _err != nil && _err == ErrKeyNotFound {
		return nil
	}
	return string(_rs)
}

func (that *raftFsm2) List() []interface{} {
	_slice := []interface{}{}
	_iter := that.db.NewIterator(nil, nil)
	for _iter.First(); _iter.Valid(); _iter.Next() {
		_key := _iter.Key()
		_val := _iter.Value()
		if bytes.Equal(_key, dbLogIndex) {
			continue
		}
		_slice = append(_slice, string(_val))
	}
	return _slice
}

func (that *raftFsm2) Set(k, v []byte) error {
	return that.db.Put(append(dbConf, k...), v, that.wo)
}

// Get is used to retrieve a value from the k/v store by key
func (that *raftFsm2) Get(k []byte) ([]byte, error) {
	val, err := that.db.Get(append(dbConf, k...), nil)
	if err != nil {
		if err == leveldb.ErrNotFound {
			return nil, ErrKeyNotFound
		}
		return nil, err
	}
	return bcopy(val), nil
}

// SetUint64 is like Set, but handles uint64 values
func (that *raftFsm2) SetUint64(key []byte, val uint64) error {
	return that.Set(key, uint64ToBytes(val))
}

// GetUint64 is like Get, but handles uint64 values
func (that *raftFsm2) GetUint64(key []byte) (uint64, error) {
	val, err := that.Get(key)
	if err != nil {
		return 0, err
	}
	return bytesToUint64(val), nil
}

//Apply flower同步写入
func (that *raftFsm2) Apply(l *raft.Log) interface{} {
	_index := l.Index
	_entry, _err := parseEntry(l.Data)
	if _err != nil {
		fmt.Println(string(l.Data), "====== raftFsm.Apply error 001 ======", _err)
		return nil
	}
	_fsmIndex, _ := that.GetUint64(dbLogIndex)
	if _fsmIndex >= l.Index {
		return nil
	}
	var batch leveldb.Batch
	_key := _entry.GetKey()
	_val := _entry.GetVal()
	if _val == "" {
		batch.Delete([]byte(_key))
	} else {
		batch.Put([]byte(_key), []byte(_val))
	}
	batch.Put(dbLogIndex, uint64ToBytes(_index))
	if _err := that.db.Write(&batch, that.wo); _err != nil {
		fmt.Println(string(l.Data), "====== raftFsm.Apply error 002 ======", _err)
	}
	return nil

}

//Snapshot 返回快照接口类型
func (that *raftFsm2) Snapshot() (raft.FSMSnapshot, error) {
	return that, nil
}

//Restore 从快照中恢复到内存
func (that *raftFsm2) Restore(r io.ReadCloser) error {
	return nil
}

//Persist 生成快照
func (that raftFsm2) Persist(sink raft.SnapshotSink) error {
	return nil
}

func (that raftFsm2) Release() {
}

// Close is used to gracefully close the DB connection.
func (that *raftFsm2) Close() error {
	return that.db.Close()
}
