package writecachebbolt

import (
	"fmt"
	"math"
	"sync/atomic"

	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/fstree"
	"go.etcd.io/bbolt"
)

func (c *cache) estimateCacheSize() uint64 {
	dbCount := c.objCounters.DB()
	fsCount := c.objCounters.FS()
	if fsCount > 0 {
		fsCount-- // db file
	}
	dbSize := dbCount * c.smallObjectSize
	fsSize := fsCount * c.maxObjectSize
	c.metrics.SetEstimateSize(dbSize, fsSize)
	c.metrics.SetActualCounters(dbCount, fsCount)
	return dbSize + fsSize
}

func (c *cache) incSizeDB(sz uint64) uint64 {
	return sz + c.smallObjectSize
}

func (c *cache) incSizeFS(sz uint64) uint64 {
	return sz + c.maxObjectSize
}

var _ fstree.FileCounter = &counters{}

type counters struct {
	cDB, cFS atomic.Uint64
}

func (x *counters) DB() uint64 {
	return x.cDB.Load()
}

func (x *counters) FS() uint64 {
	return x.cFS.Load()
}

// Set implements fstree.ObjectCounter.
func (x *counters) Set(v uint64) {
	x.cFS.Store(v)
}

// Inc implements fstree.ObjectCounter.
func (x *counters) Inc() {
	x.cFS.Add(1)
}

// Dec implements fstree.ObjectCounter.
func (x *counters) Dec() {
	x.cFS.Add(math.MaxUint64)
}

func (c *cache) initCounters() error {
	var inDB uint64
	err := c.db.View(func(tx *bbolt.Tx) error {
		b := tx.Bucket(defaultBucket)
		if b != nil {
			inDB = uint64(b.Stats().KeyN)
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("could not read write-cache DB counter: %w", err)
	}
	c.objCounters.cDB.Store(inDB)
	c.estimateCacheSize()
	return nil
}