package engine

import (
	"time"

	"git.frostfs.info/TrueCloudLab/frostfs-node/internal/metrics"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
)

type MetricRegister interface {
	AddMethodDuration(method string, d time.Duration)

	SetObjectCounter(shardID, objectType string, v uint64)
	AddToObjectCounter(shardID, objectType string, delta int)

	SetMode(shardID string, mode mode.Mode)

	AddToContainerSize(cnrID string, size int64)
	DeleteContainerSize(cnrID string)
	DeleteContainerCount(cnrID string)
	AddToPayloadCounter(shardID string, size int64)
	IncErrorCounter(shardID string)
	ClearErrorCounter(shardID string)
	DeleteShardMetrics(shardID string)

	SetContainerObjectCounter(shardID, contID, objectType string, v uint64)
	IncContainerObjectCounter(shardID, contID, objectType string)
	SubContainerObjectCounter(shardID, contID, objectType string, v uint64)

	IncRefillObjectsCount(shardID, path string, size int, success bool)
	SetRefillPercent(shardID, path string, percent uint32)
	SetRefillStatus(shardID, path, status string)
	SetEvacuationInProgress(shardID string, value bool)

	WriteCache() metrics.WriteCacheMetrics
	GC() metrics.GCMetrics
}

func elapsed(method string, addFunc func(method string, d time.Duration)) func() {
	t := time.Now()

	return func() {
		addFunc(method, time.Since(t))
	}
}

type gcMetrics struct {
	storage metrics.GCMetrics
	shardID string
}

func (m *gcMetrics) SetShardID(id string) {
	m.shardID = id
}

func (m *gcMetrics) AddRunDuration(d time.Duration, success bool) {
	m.storage.AddRunDuration(m.shardID, d, success)
}

func (m *gcMetrics) AddDeletedCount(deleted, failed uint64) {
	m.storage.AddDeletedCount(m.shardID, deleted, failed)
}

func (m *gcMetrics) AddExpiredObjectCollectionDuration(d time.Duration, success bool, objectType string) {
	m.storage.AddExpiredObjectCollectionDuration(m.shardID, d, success, objectType)
}

func (m *gcMetrics) AddInhumedObjectCount(count uint64, objectType string) {
	m.storage.AddInhumedObjectCount(m.shardID, count, objectType)
}

type (
	noopMetrics           struct{}
	noopWriteCacheMetrics struct{}
	noopGCMetrics         struct{}
)

var (
	_ MetricRegister            = noopMetrics{}
	_ metrics.WriteCacheMetrics = noopWriteCacheMetrics{}
	_ metrics.GCMetrics         = noopGCMetrics{}
)

func (noopMetrics) AddMethodDuration(string, time.Duration)                  {}
func (noopMetrics) SetObjectCounter(string, string, uint64)                  {}
func (noopMetrics) AddToObjectCounter(string, string, int)                   {}
func (noopMetrics) SetMode(string, mode.Mode)                                {}
func (noopMetrics) AddToContainerSize(string, int64)                         {}
func (noopMetrics) DeleteContainerSize(string)                               {}
func (noopMetrics) DeleteContainerCount(string)                              {}
func (noopMetrics) AddToPayloadCounter(string, int64)                        {}
func (noopMetrics) IncErrorCounter(string)                                   {}
func (noopMetrics) ClearErrorCounter(string)                                 {}
func (noopMetrics) DeleteShardMetrics(string)                                {}
func (noopMetrics) SetContainerObjectCounter(string, string, string, uint64) {}
func (noopMetrics) IncContainerObjectCounter(string, string, string)         {}
func (noopMetrics) SubContainerObjectCounter(string, string, string, uint64) {}
func (noopMetrics) IncRefillObjectsCount(string, string, int, bool)          {}
func (noopMetrics) SetRefillPercent(string, string, uint32)                  {}
func (noopMetrics) SetRefillStatus(string, string, string)                   {}
func (noopMetrics) SetEvacuationInProgress(string, bool)                     {}
func (noopMetrics) WriteCache() metrics.WriteCacheMetrics                    { return noopWriteCacheMetrics{} }
func (noopMetrics) GC() metrics.GCMetrics                                    { return noopGCMetrics{} }

func (noopWriteCacheMetrics) AddMethodDuration(string, string, string, string, bool, time.Duration) {}
func (noopWriteCacheMetrics) SetActualCount(string, string, string, uint64)                         {}
func (noopWriteCacheMetrics) SetEstimateSize(string, string, string, uint64)                        {}
func (noopWriteCacheMetrics) SetMode(string, string)                                                {}
func (noopWriteCacheMetrics) IncOperationCounter(string, string, string, string, metrics.NullBool)  {}
func (noopWriteCacheMetrics) Close(string, string)                                                  {}

func (noopGCMetrics) AddRunDuration(string, time.Duration, bool)                             {}
func (noopGCMetrics) AddDeletedCount(string, uint64, uint64)                                 {}
func (noopGCMetrics) AddExpiredObjectCollectionDuration(string, time.Duration, bool, string) {}
func (noopGCMetrics) AddInhumedObjectCount(string, uint64, string)                           {}