package merkletrierepo

import (
	"io"

	"github.com/cockroachdb/pebble"
	"github.com/pkg/errors"
)

type Pebble struct {
	db *pebble.DB
}

func NewPebble(path string) (*Pebble, error) {

	cache := pebble.NewCache(512 << 20)
	//defer cache.Unref()
	//
	//go func() {
	//	tick := time.NewTicker(60 * time.Second)
	//	for range tick.C {
	//
	//		m := cache.Metrics()
	//		fmt.Printf("cnt: %s, objs: %s, hits: %s, miss: %s, hitrate: %.2f\n",
	//			humanize.Bytes(uint64(m.Size)),
	//			humanize.Comma(m.Count),
	//			humanize.Comma(m.Hits),
	//			humanize.Comma(m.Misses),
	//			float64(m.Hits)/float64(m.Hits+m.Misses))
	//
	//	}
	//}()

	db, err := pebble.Open(path, &pebble.Options{Cache: cache, BytesPerSync: 32 << 20, MaxOpenFiles: 2000})
	repo := &Pebble{db: db}

	return repo, errors.Wrapf(err, "unable to open %s", path)
}

func (repo *Pebble) Get(key []byte) ([]byte, io.Closer, error) {
	d, c, e := repo.db.Get(key)
	if e == pebble.ErrNotFound {
		return nil, c, nil
	}
	return d, c, e
}

func (repo *Pebble) Set(key, value []byte) error {
	return repo.db.Set(key, value, pebble.NoSync)
}

func (repo *Pebble) Close() error {

	err := repo.db.Flush()
	if err != nil {
		// if we fail to close are we going to try again later?
		return errors.Wrap(err, "on flush")
	}

	err = repo.db.Close()
	return errors.Wrap(err, "on close")
}

func (repo *Pebble) Flush() error {
	_, err := repo.db.AsyncFlush()
	return err
}